Game Programming

ECS Concepts - Part 1: Background

by Cory on August 30, 2017 2:02 AM (Edited August 30, 2017 2:04 AM)

Hey kids, guess what? It’s finally time for Cory to update his fucking blog. I got my code to a point that I’m willing to call “Milestone 1”. It has the E, the C, AND the S. Booyah. I wanted to wait until after I finished fully implementing an ECS so I could polish my write ups without having to change things as I went along and that’s why it took so long. Actually it took so long because I spent a lot of time playing games and watching TV... Anyway enough about me, how are you???

You might notice that I called this post “Part 1”. That’s because I’m going to try and discuss in great detail what I did to implement my own framework and at the same time, try and gather up all the supremely useful links, resources, and bits of knowledge into one place.

What is an ECS?

An ECS stands for “Entity Component System”. It’s a framework paradigm for game design and other large programs that takes advantage of the OOP principle of composition to create objects with complex behaviors without having to drastically redesign the program. That was a whole bunch of buzzword mumbo-jumbo but it was the best way to summarize it in one sentence. You should come back and read this paragraph again later. And if I already lost you, don’t worry. Just read this first (it’s really short, I promise):

https://www.gamedev.net/articles/programming/general-and-gameplay-programming/understanding-component-entity-systems-r3013/

This dude emphasizes 2 things.

  1. Using the (not-at-all specific to ECS) programming principle of “composition”, you can create new entities with complex behaviors without having to deal with deep inheritance trees or having to redesign your entire hierarchy when you want to add new functionality.

  2. Entities and components should be pure data and systems should have all the logic. That’s in theory, but it should be the guideline you want to strive for.

 

I don’t think it’s obvious why these two things are important at this point. I’ll explain them in much more detail in later posts.

The ECS part of your game engine isn’t the whole engine. It’s just one big part of the engine that needs to communicate with other components like the scene graph or graphics pipeline. You’ll still probably have rendering code and input handling and maybe a physics engine and a whole lot of other low level stuff that shouldn’t belong in an ECS. The framework’s job is to standardize a large portion of functionality that is expected of video games (and does it very well, imo). I guess you could say that it encapsulates game logic.

Ok and that’s it—that’s the high level summary. Back when I first started, I spent an entire day going around and reading different peoples’ descriptions to get a good enough idea to implement one of these damn things. Everything I wrote until here was just basic shit that you could get from a quick google search. From here on out, I’m going to try and provide intuition (partially gained from personal experience) and rationale for why you want to design certain things in a specific way. To the best of my knowledge that is. I only implemented one but I haven’t actually used it yet...

Entities: an Intuition

An entity is anything that you can consider a game object. You don’t want everything in your game to be an entity because there are lots of things that you can get away with simplifying. If you hook in a physics solver or a 3rd party graphics engine, you wouldn’t want your graphics primitives to be entities most likely, for instance. You want those graphics primitives to be as small and fast to draw as possible. And you also probably don’t want your game logic being mixed up in the graphics pipeline.

Ok so keeping that in mind what I should have said was that an entity is anything that you can consider a game object AND you need to be able to customize it’s behavior AND you modify via a System.

Examples of entities can include the player character, enemies, random pieces of shrubbery, bullets, UI elements, etc. Since these things are going to be operated on systems for moving them around, subtracting health, creating and destroying them, clicking on them, and so on.

Components: an Intuition

Components are little modules that you can add on entities to gain extra functionality. For instance, if you want an enemy to be able to fly, you could create a FlyingComponent and attach it to your enemy entity so that it is now marked with the ability of flight. Similarly, you could create a MagicComponent to give the same entity magic spell attacks or some shit.

Components separate various different game properties into discrete functional units that you can bolt onto entities a la carte. This is in stark contrast to using inheritance hierarchies to add functionality. You could accomplish the same thing if you had an enemy entity that inherited from an interface IFlying and from the interface IMagic. However, this is a rigid software design because the two interfaces are intimately coupled with the class definition. If you wanted to make non-magic enemies or non-flying magic enemies, you need to make new classes, most likely with a lot of duplicated code. And that’s not an ECS specific thing, it’s just good software engineering practice to “prefer composition over inheritance”.

Now read this article. Do it. Do it now:

http://t-machine.org/index.php/2012/03/16/entity-systems-what-makes-good-components-good-entities/

The main takeaway here is that components should be easy to make and that you will probably end up making a lot of them. When I first started out, I thought some good components would be “Graphics”, “Physics”, and “Sound”. But those are too general and big to be components. My original idea for Graphics would be a sprite that contained logic to draw itself to screen. It was able to perform graphical manipulations of itself (resizing, blending, etc). That doesn’t belong here. You want components to be finer grained, like “Sprite”, “Rectangle”, “Health”, “Defense”, and “Position”, and fucking stupid as shit. Components should be data only objects. Just dumb little structs that contain variables and as little logic as possible. This might go against OOP principles at first glance, but ECS paradigm is trying to keep the business logic away from the data.

You’ll end up with small components like “Position” and “Velocity” that are basically just structs with two variables. If you recall from the previous link, their example had a buttload of components that were ridiculously specific. I mean, c’mon. “ReputationValue”? “MovesOnClick”? Those are probably just a single variable each. But that’s good. They contain just enough data for the system to know what to do with them. Also don’t forget that the mere fact that the component is attached to an entity is also a way of telling the system how it should treat the entity. That’s a key piece of information.

So take my hypothetical Position component from before. You might write it like this:

class Position : public Component {
public:
int x;
int y;
};

Simple as that. “How does anything work???”, you might ask. Don’t worry your pretty little head about it. All of that is taken care of in the system layer. But the important revelation I had when figuring out how to make components was this: You want to create skinny entities/components and fat systems.

Systems: an Intuition

This one is difficult… I’m going to be honest, there is a still a lot of work for me to build up my system design since this part of the framework is so open ended. I can try to describe the necessary ingredients that make up a system and hopefully that will help. While entities and components were just containers for information, the system is where it all comes together.

Every system operates on entities. Each system needs to know whether or not to operate on a given entity based on the components that it has attached to the aforementioned entity. For instance, you could have a PhysicsSystem that operates only on entities that have a mass component AND a velocity component AND a position component. If one of these components is missing from an entity, the system ignores this entity. In each update of the game loop, the PhysicsSystem would iterate through all entities that meet the criteria and update the x and y coordinates of the Position component based on the values of the velocity and mass components.

Another example is when you have a system just for controlling the player character. This system is supposed to listen to the input for when the user presses buttons and then updates the position or state of the player character to match. This system would require a position component. But how do we identify the player character? (Because if we stopped here, the system would operate on every entity that had a position component). We could make a special component called “PlayerCharacter” that is only attached to the player character entity and nothing else. If we tell the system to look for this component in addition to the position component then only this entity will be moved by the system. Also note that this PlayerCharacter component can be completely empty for all we care at this point. We added the component just to record the fact that this entity is the player character. No other information was required.

Another big thing that systems need is an event or messaging framework. Systems will need to talk to each other eventually and they do so via messages or events. For example, there might be a system that handles player inventory and another system that handles behavior of interactive objects like treasure chests. When the player character walks up to a chest and opens it, the map object system will despawn the chest and send a message to the inventory system to move the contents of the destroyed treasure chest to the player’s inventory. There are going to be a lot of messages flying this way and that. Sometimes you’ll need to broadcast a one to many message like when an entity is destroyed. Some systems will need to be aware of this event and clean up enemy graphics, or throw up a victory screen or something. Messaging is super important and probably going to be a huge pain in the ass to debug.

Robert Nystrom talks about messaging and event queues in his book. He also has a section where he talks about the distinction between “message” and “event”. Basically, a message is something that is sent to initiate future action and an event is a thing that is sent to describe actions that have already happened. You can read more here:

http://gameprogrammingpatterns.com/event-queue.html#what-goes-in-the-queue

And one more thing.

Did I say “fat system” before? Well, it doesn’t have to be fat, but if it ends up being fat, that’s okay. You could instead have smaller systems that do a little bit of work, but have a lot of them working together. That’s okay too. Both of these setups are fat in spirit. So there.

To be Continued

I’ll start going over specific code and implementation details about the above items in my next posts. I’ll have those coming out on a quicker schedule. I’m thinking every couple of days or so? I think that’s where the real interesting part starts. Unless you aren’t a loser like me and you’re not obsessed with tiny programming details.

One last really useful resource I want to mention is the Artemis-odb wiki site. Artemis-odb is an ECS framework written in Java. Their documentation is so-so but contains enough implementation details for me to steal and infer how things are supposed to work. You can take a look at the docs here:

https://github.com/junkdog/artemis-odb/wiki



This Thought is part of Game Programming

Game programming general topic. I eventually hope to split this into separate ideas exclusively about specific games that I make.

back to the

top