Catherine West gave an excellent closing keynote to Rust Conf on using Rust for game development which delved into using an ECS at the core of a game engine and in particular focusing on Data Driven architecture over a more traditional OOP approach.
What is an Entity-Component System (ECS)
ECS is an inversion of the OOP principals. Rather than workig from a subject-verb perspective, that is “The Dog acts,” we invert the language to make the verb promenent: “The Dog is acted upon.”
We do this by removing all data and methods from the “Dog” entity, and focus our design around verbs: input, animate, render, etc. The verbs are components, the thing acted upon is an entity which is a type.
This is a kind of Data Driven Programing where the data defines the implementation details of the business logic rather than the code defining the available business methods.
What is the Benefit of an ECS
An ECS removes the need to hard-code business relationships between entities such that rapid prototyping of business logic becomes possible.
This results in:
- Building systems where stakeholders can modify business rules on the fly
- Building concepts that cross-cut through many objects
- Increased agility
- Can take advantage of parallel processing
- Becomes a replacement of the observer pattern
Cowboy Programming in Evolve your Heirarchy describes some of the disadvantages of moving forward without an ECS. Namely, a deep heirarchy that is difficult to manage, and the creation of god-objects to resolve common code duplication.
Notes on Implementation
T-Machine posits in Entity Systems are the Future that an ECS is not a programming paradigm but a type of system that exists in a larger OOP application that solves issues that OOP handles poorly. In practice it becomes an encoding of our business relationships into either a in-memory RDBMS or atual RDBMS (depending upon thuroughput needs).
A component, according to T-Machine, is an aspect of an entity. It contains a bucket of properties that define the entity from that aspect.
A system, according to T-Machine, contains all the actions that can be performed to mutate a component. A system performs it’s actionas against all entities with a particular aspect.
Example: We have dog-1, dog-2, dog-3. Each is an entity (in production usage these would be GUIDs). Each of these entities is entered into the component table as having the moveable component which pivots to a table defining the position and velocity. The move system runs, applies velocity to each component’s position and then updates the position properties.
In practice our table structure looks like:
Finally the component data table (“movement”)
As an explanation of the above, we have three entities and three components. The first entity is renderable and movable, the second entity is movable (but not renderable). Looking into the movement table we see the first entity has an x/y position and is moving along the x axis. The second entity has an x/y position and is moving on the y axis.
We can add and remove entities from these tables.
T-Machine also notes that we can have “assemblers” to create various component quickly by bundling together similar collections of components and naming them. I do wonder if some factory or abstract factory style pattern fits in there.