Gian Saß

An Overview of the Entity-Component-System

· Gian Sass

Game programming traditionally revolved around the concept of inheritance, that is, game objects and entities inherit functionality, and become more specific in their functioning as the inheritance gets more complex.

But this type of architecture has evolved to be, in most cases, inefficient. As the game matures, functionality becomes increasingly complicated, which often results to deeply rooted chaos. To combat this cause, game programming has shown that the concept of Composition over Inheritance in such matters have turned out to be (sometimes) more efficient than an architecture based on inheritance.

The point of composition is simple. Rather than inheriting functionality, entities should have the functionality. In such a way behavior is more dynamic than inheritance, because _components _(which define that functionality) can be added, removed, and interchanged at runtime, whereas inheritance is fixed (you cannot change your parents). These two different concepts are also called has-a and is-a.

Basic Structure

In theory the Entity-Component-System is very simple. As the name says, the Entity-Component System, let’s call it ECS for now, is based on three things: entities, components, and systems.

Entities are things that live. They are the owner of components and are defined only by them. Entities are sole components containers, much like organisms are containers of genes – it is up to the genes how that organism behaves. Super power of programming: we can change the genes!

Typically, an entity would be defined by a unique ID. This would remove the problem of passing pointers, for they could get invalidated after an entity ceases to exist. Additionally it makes it easier to save entities, say, in a save-state file – there would be no need to reconstruct pointers.

class Entity {
public:
    unsigned int id;
    std::vector<Component*> components;
    ...
}

Components are simple data-structs which hold some type of data relevant to its purpose. As said before, they could be called the genes of entities. Examples include a PhysicsComponent with coordinates and velocity. Or a HealthComponent which tracks health, etc. The basic idea of components is that they act as storage for relevant data, and nothing more. Combined, they build up the essential functionality of entities, an organism.

struct PhysicsComponent {
    Vector2 position, velocity;
}

Say, you have an entity that builds an NPC, that would have a PhysicsComponent, FriendlyAIComponent, HealthComponent, etc. Now, with the magic of ECS, it is easy to turn this NPC to a zombie. How? Just by swapping FriendlyAIComponent with ZombieAIComponent!

Finally, the concept of a system is what actually brings these data structures alive. Systems make things move. They interact with components according to their data. For example, one may have a PhysicsSystem, HealthSystem, etc. Per frame, these would iterate through existing entities and update their specific components. The PhysicsSystem would for example add velocity to position, the HealthSystem might check for entities which have died, and clean up the entity, or trigger some kind of health regeneration. It is up to the designer how specific the systems are involved.

void Update() {
    PhysicsComponent *pc = NULL;
    for(Entity *entity : entities) {
        if((pc = entity->GetComponent<PhysicsComponent>())) {
          pc->position += pc->velocity;
        }
    }
}

Summary

One of the major drawbacks of ECS is the tremendous amount of iteration one has to do. Then, as more entities and components are added, the game will get slower. Compared with other design architectures, ECS has no substantial benefits, other than its dynamics in handling components. In the end it is clearly a matter of choice. I hope I gave you an idea on ECS and how clever it is!