Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
October 23, 2019
arrowPress Releases







If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

A Game Programming Experiment

by Hendrik du Toit on 04/08/19 11:02:00 am

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

Motivation

I started an experiment to try and create the silver bullet of design patterns when writing game code. I’ve done roughly four iterations of it already (mainly using it for academic assignments) but I wouldn’t call it a silver bullet just yet. Maybe just a bullet for now. I am, however, sharing this to try to create some traction for people that share my motivations.

I also want to try to create something more strictly established than ECS. To achieve that, I’ve aimed to tackle three problems that I’ve struggled with when dealing with gamedev code in general: avoiding singleton/reference hell, focusing on easy/fast engine adoption that supports designers, and improving efficiency by allowing teams to reuse previously developed systems.

Rules

I want to start off by defining the five rules required for this experiment to succeed:

  1. Components are just data.They are also the only things scripts or editors have to access and alter gameplay at runtime.
  2. Systems process data. Systems are only concerned with component data and other connected systems.
  3. No crashes occur during runtime if a component/system is added/removed/updated.
  4. Systems can function independently and within a sandboxed/multithreaded environment.
  5. Game objects (or entities) only serve to group components together.

Game Event Buffer

The first aspect is the simplest and is essentially the easiest part to understand: events. Everything that can happen in our game will be defined as an event and will be considered the moving parts that make a game simulate.

Defining these events are also a powerful first step when you start planning your game. You could even go as far as defining every single one of them in your GDD. How to define these events are up to you but you’ll probably only get the hang of it after understanding systems and components.

Systems 

Apart from processing component data, systems are also where we will define our game events. Let’s create a system and call it CharacterSystem. To enforce rule #3, we have to make sure that if we rip out this system, changing the state of the character in our game should not be possible anymore. That is why we also define our character related events within systems. We should, however, be careful. Doing something like removing a system mid game loop when there could be dependencies will most likely crash the game, violating rule #3. That is why events are essentially just integers whose values only exist inside of buffers. Which brings us to components.

Components

You are probably used to components from patterns like ECS or just from game engines. However, these components are a bit different. They only do up to two things:

  1. Expose properties to designers or scripts.
  2. Store buffers of events coming from or used by systems.

When you reach the example, point #2 above is actually done for you by the EZS plugin, but it is important to understand why these buffers exist.

It is also important to remember rule #1. These components cannot contain any logic. They are meant to be stupid and that stupidity helps enforcement of rules #2, #3, and #4.

To conclude your understanding of the experiment, we first need to paint a picture. By picture, I mean let's use the things we know so far and create a little scenario. Then we will visualize how an event traverses through our buffers within a single game loop.

The life of a game event

For our systems we’ll create two:

 

And each system will have its component:

 

Of course our event should also exist somewhere. I’m going to keep it simple and define just one event and call it ToggleWeapon. We add it in the CharacterSystem because it relates to the character’s weapon and the event shouldn’t exist anymore if that system is remove/disabled:

 

Remember our components all have what we call a buffer of events. They get used by systems (if they are registered) to react on what the event is meant to perform. In our case, the KeyboardComponent will also be storing bindings triggered by KeyboardSystem which will add an event to its buffer. When the key is pressed we still only have the ToggleWeapon event sitting in the KeyboardComponent event buffer:

 

We need to get the event into the CharacterComponent, so the CharacterSystem that owns the code to toggle the weapon can process its buffer. To achieve this we create another system, an intermediate between the two, which is the final aspect to the experiment:

If either of the systems are removed/disabled, the same has to happen to the intermediate system. There is potential for good Venn diagrams in our GDD here but more on that later.

 

Now we can invoke an event from the KeyboardSystem that will eventually end up in the CharacterSystem and do exactly what we need it to do. I’ve added numbered arrows to show the flow of the ToggleWeapon event’s life, which ends once it is processed by the CharacterSystem:

 

Example (Unity3D)

I’ve put the scenario above into a .unitypackage that you can try for yourself. It comes with a library I developed called EZS and it takes care of all of the low level stuff. It also (hopefully) allows for easy adoption so designers can focus on just creating events, systems, and components. I haven’t gone through the effort of documenting it either, so some of the stuff might seem a bit foreign. I am, however, hoping that the simplicity of the API will help it teach itself to you by example and based on the content of this article.

Download link for the latest build and examples: https://github.com/fanus/ezs-unity/releases

Conclusion

I’ve found that encapsulation is pretty liberating when it comes to designing code, but I believe it has even greater potential when developing games. Systems often need to be reworked due some obscure bug or a mechanic that profoundly supports gameplay. Planning can also be hard to solidify upfront because you can’t always predict what will happen until something is actually played. By keeping our systems and naively engineered mechanics in a state of flux, we should be able to conveniently iterate over systems and eventually develop more player centric games.

Next Steps

I will be developing a mini game using this approach. The goal is to continuously improve, solve issues, and consider feedback as I go along. So expect more examples and diagrams.


Related Jobs

Sucker Punch Productions
Sucker Punch Productions — Bellevue, Washington, United States
[10.22.19]

Camera Designer
Deep Silver Volition
Deep Silver Volition — Champaign, Illinois, United States
[10.22.19]

Gameplay Programmer
University of Utah
University of Utah — Salt Lake City, Utah, United States
[10.21.19]

Assistant Professor (Lecturer)
HB Studios
HB Studios — Lunenburg/Halifax, Nova Scotia, Canada
[10.21.19]

Experienced Software Engineer





Loading Comments

loader image