┌───────────┐   ┌───────────┐   ┌───────────┐   ┌───────────┐                      
              │ Entity    │   │ Entity    │   │ Entity    │   │ Entity    │                      
              │  Position │   │  Position │   │  Position │   │  Position │                      
   entity     │   x       │   │   x       │   │   x       │   │   x       │                      
   type 1     │   y       │   │   y       │   │   y       │   │   y       │                      
              │  Velocity │   │  Velocity │   │  Velocity │   │  Velocity │                      
              │   xVel    │   │   xVel    │   │   xVel    │   │   xVel    │                      
              │   yVel    │   │   yVel    │   │   yVel    │   │   yVel    │                      
              └───────────┘   └───────────┘   └───────────┘   └───────────┘                      
                                                                                                 
                                                                                                 
                                                                                                 
              ┌───────────┐   ┌───────────┐    ┌───────────┐                                     
   entity     │ Entity    │   │ Entity    │    │ Entity    │                                     
   type 2     │  Health   │   │  Health   │    │  Health   │                                     
              │   hp      │   │   hp      │    │   hp      │                                     
              │   regen   │   │   regen   │    │   regen   │                                     
              └───────────┘   └───────────┘    └───────────┘                                     
                                                                                                 
                                                                                                 
                                                                                                 
              ┌───────────┐    ┌───────────┐    ┌───────────┐    ┌───────────┐    ┌───────────┐  
   entity     │ Entity    │    │ Entity    │    │ Entity    │    │ Entity    │    │ Entity    │  
   type 3     │  Health   │    │  Health   │    │  Health   │    │  Health   │    │  Health   │  
              │   hp      │    │   hp      │    │   hp      │    │   hp      │    │   hp      │  
              │   regen   │    │   regen   │    │   regen   │    │   regen   │    │   regen   │  
              │  Position │    │  Position │    │  Position │    │  Position │    │  Position │  
              │   x       │    │   x       │    │   x       │    │   x       │    │   x       │  
              │   y       │    │   y       │    │   y       │    │   y       │    │   y       │  
              │  Velocity │    │  Velocity │    │  Velocity │    │  Velocity │    │  Velocity │  
              │   xVel    │    │   xVel    │    │   xVel    │    │   xVel    │    │   xVel    │  
              │   yVel    │    │   yVel    │    │   yVel    │    │   yVel    │    │   yVel    │  
              └───────────┘    └───────────┘    └───────────┘    └───────────┘    └───────────┘  
                                                                                                 

────────────────────────────────────────────────────────────────────────────────────────────────                                                               
                                                                                                 
                                                                                                 
              ┌────────────┐   ┌──────────────┐  ┌─────────────────┐                             
              │            │   │              │  │                 │                             
   systems    │ MoveSystem │   │ DamageSystem │  │  WeatherSystem  │                             
              │            │   │              │  │                 │                             
              └────────────┘   └──────────────┘  └─────────────────┘                             
                                                                                                                                                       

Introduction

Hello! Today, we’ll be talking about a neat way to organize your code when you are making games, simulations, robotics, etc. It’s called Entity Component System (ECS).

ECS is a software architecture pattern that is often used in fields like game dev, simulation, robotics, etc, but also just whenever you are managing a large number of entities with varying behaviors.

Here’s the basics of how it works. An Entity is just an identifier, an id, nothing more. A Component is just some data, a struct, nothing more (no behavior!). A system is a function that processes entities that have certain components, every frame.

In your main loop, every frame, you call each system, passing in the entities they operate on.

on_frame:
    for system in all_systems:
        system(get_entities_for_system(system))

The system will do stuff to the entities, like move em, etc, basically change the data in their components.

Performance Benefits

In fields such as game dev, simulation, etc, you generally have to loop through all the entities every frame and run some code on them. As you are running through the entities, you are calling methods on them, which obviously executes some code, some function on the entity’s attributes/data. As these functions are executing, they are fetching data from your list of entities, but you are getting a lot of cache misses because the methods of different types of entities operate on wildly different data.

In ECS, you generally keep entities that have the same components, close together in memory, usually contiguous. For example, all entities that have a Position and Velocity component are stored contiguously in memory. All entities that have a Position, Velocity, and Health component are stored contiguously in memory, etc.

Let’s say that a system, MoveSystem, needs to loop through all entities that have a Position and Velocity component. As this system is looping through these entities, it is likely that the data it needs is already in the CPU cache! Remember, that a CPU fetches data from memory in chunks, and places the extra data in the cache. A cache line is usually 64 bytes. So a CPU fetches 64 bytes of data from memory at a time.

CPU stalls, when a CPU experiences a cache miss, are extremely expensive. By looping through contigeous entities, the sytem code runs much faster.

Maintainability and Extensibility

Performance benefit from locality isn’t the only benefit of ECS. ECS focuses on composing objects from composition rather than inheritance, which we all know is much more flexible.

For example, in traditional inheritance, you might have a MoveableEntity class, a DamageableEntity class, etc. Based on what the entity needs to do, you would have it inherit from other classes. This can sometimes lead to diamond inheritance, for example if a class needs to both move and be damageable.

What if instead of using inheritance, we use composition? What if we give the class a MoveableComponent and a DamageableComponent? By simply giving the entity the correct components, the correct system(s) will operate on it and thus it will have the correct behavior!

Flexibility

Furthermore, entities can dynamically change components, and thus change behavior. This is far more flexible than changing what you inherit from when you want to change behaviors!

In ECS, you worry about what an Entity has rather than what it is!

Conclusion

Let’s keep it short!

  • ECS is a software architecture pattern that is often used in fields like game dev, simulation, robotics, etc, but also just whenever you are managing a large number of entities with varying behaviors.
  • ECS is great for performance, maintainability, and flexibility. It prioritizes composition over inheritance, and allows for dynamic behavior changes simply by adding/removing/swapping components.
  • The performance gain is basically from locality and thus cache hits.