Entity Component Systems
Entity Component Systems (ECS)
Over the past decade or so, there has been quite a drive to more and more make games using an ECS. Of course, this is just a pattern and before applying a pattern, we should ask ourselves why.
Any cursory reading on the subject, and there are enough articles to read on it that you could spend a week just reading them, will tell you that a primary reason to use an ECS is to create Data Driven Games. This flies in face of normal Object Oriented Design which was its primary predecessor.
As your game gets larger and larger, OOP starts to fail with inheritance becoming unwieldy. A common argument goes as follows.
I have an NPC. Let’s say he’s a human. I give him a sword. So, I likely have an NPC class, Human inherits from that, and swordsman inherits from Human.
Now I want a human with a spear. Easy, I just inherit Spearman from Human. In comes Orcs. Orc inherits from NPC. Now I have OrcSwordsman…OrcSpearman…etc. Unless I get really clever, I have a lot of code duplication.
I forgo classic inheritance in favor of composition.
An NPC has a Race. It has a Weapon. - Much more simple….
Now, the more I code in general, the more I favor composition over inheritance (as does Go) so this should be an easy argument for me to make.
An ECS is really just a pattern which allows for a framework to allow for composition on the highest level.
Let’s start with Component… A Component is nothing more than a struct containing data. That’s it. We may create, for instance, a Position component. It would have an X and a Y element. We could attach this component to virtually anything which would take space in our world. A player…an Orc…even a chair. If it exists and we need to track its position, we add this component to that entity…
Which brings us to Entity… An entity is actually nothing more than a grouping of components. In most ECS implementations, the Entity is assigned a unique ID, but other than that, it contains nothing else but a collection of the components attached to it. Components may be dynamically attached to an entity, or they may be attached when an entity is created (the concept of prefabs in many game engines comes from this idea).
Now we are left with Systems…
If a component is simply data, and an entity is simply the grouping of that data, a System is a function which acts on that data.
A Render System, for instance, could draw EVERY entity which has the Renderable component. Or, it could be limited to only drawing entities which have both a Renderable and a Position component, where the Position is within the screen boundaries.
A Collision System would obviously work on all entities with a Position component and a Collideable component.
The simple act of adding a component to an entity will automatically have it registered for these systems to act on.
This can have side effects: Look up Dwarven Fortress Cats Dying for a great example of unintentional (but absolutely true to the games rules) side effects of any given action.
We will be using an ECS on the Roguelike Tutorial because it allows for amazing flexibility later on. I considered writing my own, as a simple one isn’t that complicated to write once you know what you want. However, I stumbled across one which not only meets all my needs, but is very intuitive to use. So, I’m going to be using ByteArena ECS for this tutorial.