Entity-Component-System architecture: interaction between systems

by noncom   Last Updated December 12, 2017 16:05 PM

I am studying the Entity-Component-System architecture philosophy. As I have read about it, a typical entity system has:

1) Entities - which are merely ID tags which have a number of components

2) Components - which contain data on various aspects of an enity that the component is responsible for

3) Systems - which update relevant components of every entity. Say, a rendering system updates the rendering component, or simply saying, draws a picture that is stored in the data of that component. A positional and movement system handles position and movement of each entity who has a corresponding component.

These statements follow from this article which in my opition tries to be the most clear and pure in it's statements -

But the author did not explain how the interaction between systems should be realized. For example, the rendering system must know the data from the positional component of an entity in order to draw it in a correct position. And so on.

So the question is - how should I implement the interaction between the various systems?

Answers 3

Quick answer to the question that you haven't asked yet: the entity ID tag is like the key to a database row in a table, you query the system(s) using that key and pluck out the info you need.

Yes it is theoretically slower than storing pointers away. No, it is not as slow as you would think because systems can look up that key O(1).

Another quick answer to a question you haven't asked yet: yes, these component systems that everyone loves lately require some infrastructure work to get them working smoothly - they don't exist just as a realignment of where data is stored =) TANSTAAFL

Patrick Hughes
Patrick Hughes
February 03, 2012 18:58 PM

Systems and Components are no restricted to 1:1 relationship, though that is a desired trait that allows parallel processing without requiring synchronization. Generally a system can operate on any number of components attached to a entity. For example consider the following typical setup:

  • Components

    • Mass
    • Acceleration
    • Velocity
    • Position
    • BoundingVolume (for collision detection)
    • Model (visual representation)
  • Systems (with components they operate on)

    • Physics: Mass, Acceleration, Velocity, Position, BoundingVolume
    • Rendering: Position, Model

This gives every system access to all the components it requres, without the need for intersystem communication (actually this communication happens implicitly via components), but at the cost of sacrificing parallelization.

yuri kilochek
yuri kilochek
August 14, 2012 14:55 PM

So the question is - how should I implement the interaction between the various systems?

Ideally they don't, not in any direct sense. The systems in an ECS all have access to the central ECS database where they can fetch entities and components attached to them. They don't talk to each other directly. They talk to the database and all run independently of each other.

enter image description here

If systems start to depend on each other a lot, many of the maintenance benefits and the ability to reason about the correctness of your engine will be lost. Of course a pragmatic solution might sometimes call for a system calling a function in another every once in a while, but you should generally seek to keep that to a bare minimum. Instead of talking directly to each other, you can have systems modify and attach components to entities in a way such that other systems can then pick up those changes and react accordingly.

[...] the rendering system must know the data from the positional component of an entity in order to draw it in a correct position. And so on.

That it can grab from the ECS database, looping through entities with renderable and position components, just as the physics system before it might loop through entities with position components and modify their position. Generally each system fits into a basic loop model:

for each entity with the components I'm interested in:
    do something with the components

... and you have to start thinking about doing things in passes, often multiple passes even if the intuitive solution is to do everything in one pass. For example, it might come more intuitively to loop through all your game entities and apply physics and respond to input and render them all in one go. That can minimize the amount of loops you have and also require less state. However, the ECS tackles this typically with multiple simpler passes and sometimes slightly more intermediary state to use from one pass to the next, but as a trade-off, it leads to a much easier system to maintain and one which is easier to change and potentially parallelize and vectorize.

It's somewhat similar to GPU programming since GPUs aren't so good at doing complex things with each iteration, so they often excel instead at doing simple things per iteration that add up to a complex task after repeatedly running through the same data with multiple, simpler passes. Unlike GPU programming, you can still potentially do much more complex things in a single pass, but each pass will represent like one logical thought: "for each of these components, apply physics", not both physics and rendering. The physics system performs its own pass just as the rendering system, living in its own isolated world, performs its own completely separate and detachable rendering pass.

In fact, in a well-designed ECS, you can remove any system from the engine and not have the codebase collapse horribly on itself because systems don't depend on each other to function. All they care about is the central database and the components they are interested in processing. They all live in their own isolated world. As a result you should be able to remove the physics system from your game, at which point motion components will cease to have physics applied, but everything else should keep on working just as before. It's extremely orthogonal in that respect.

Event-driven programming can be a bit awkward with ECS, but one straightforward way to solve that is to have event queue components. A system can push events to these queue components for another system to pop and process in a deferred fashion without the first system directly calling functions in the second. Again the bulk of your interactions should not be system->system, but system->ECS, and system->component.

December 12, 2017 15:37 PM

Related Questions

Build a large scale backend server

Updated October 24, 2017 21:05 PM

A layer of abstraction too far?

Updated June 26, 2015 15:02 PM