Entity Component Systems: How does the system know on what Entity to work on?

Started by
8 comments, last by Norman Barrows 6 years, 10 months ago

    Hey y'all!

I am planning to implement an Entity Component System for practice and I did some research on the net
on how to do it. I have even found a nice example-implementation on gamedev: https://www.gamedev.net/resources/_/technical/game-programming/implementing-component-entity-systems-r3382

Before I go on: I really like the bitmask approach of the author and his/her concise article. Really appreciate that.

Two things popped out to me:

1.) The author talks about cache coherency. To my understanding cache coherency is about having data synchronized between different caches. What the ECS could benefit from though is exploiting locality on the cache so that all the components are next to each other in the cache and not all over the place which results in less cache misses in theory. Please correct me if I am wrong about this thought.

2.) Also, in this implementation every system (which is basically just a function) iterates over ALL entities and does the "does this entity have the required components attached?" - thing, which in my opinion, is a waste of tame. I am thinking of a way giving the systems actually all the entities it really needs, not sure about a concrete implementation yet.

What do you guys think? Would love to read your comments on that. Thank you :)

Advertisement
Where possible, systems can operate on components directly, with no knowledge of entities at all. If the system owns a contiguous array of components, it can just iterate over them.

I'm still an ECS noob myself so I won't say much about cache coherency, though your understanding seems accurate to me. But regarding 2, yeah that sounds really inefficient because it is. If the physics system has to loop through every entity and check for a collider component, or the rendering system needs to iterate and look for renderable components, you'll be doing a ton of wasteful searching. As Hodgman stated, these systems should probably have localized references to components relevant to them.

Additionally, look into the observer pattern (https://en.wikipedia.org/wiki/Observer_pattern) for event-driven communication between systems and components.

I am thinking of a way giving the systems actually all the entities it really needs, not sure about a concrete implementation yet.

The rather straightforward way is just to notify all systems when an entity is either added or removed from the simulation.

You will have a way to add or remove an entity to the simulation eventually, something like I dunno, scene.addEntity, world.addEntity, game.addEntity, etc.

There is your chance to let the systems know such thing happened, so the systems can check if the entity is of any use for them (ie, if it has the necessary components). If it is, then the system keeps the entity in its own entity list which knows wont be missing anything important. The system will use this internal list when it is time for processing the system.

When an entity is removed, you notify all systems, and if a system had that entity, it removes it from its internal list.

Think that an entity will be processed many times, and with an explicit added/removed step you only pay the "filter" cost once, when it matters.

Fastest way to filter entity components I know is just to use a bit mask to mark what components an entity has, and another mask to mark which components a system needs, so all you need to do is (entityBits & systemBits) != 0 and you'll know if it should belong to the system's entity list or not.

EDIT: Also you might need more "advanced" filtering like "add an entity if it doesn't has this component" or "add an entity if it has any of these components", etc. All pretty workable with bitsets.

Anyway, in my ECS framework I accumulate removed, added and mutated (ie, component added/removed) entities in lists inside my game World instance. Then, in the step of the game loop, before processing all the systems, I hand each list to each system so they can re-assemble their internal "active" entity list. Then I process all systems. This is nice because it is very deterministic, you wont have a system adding entities to its active list in the middle of the frame.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

Where possible, systems can operate on components directly, with no knowledge of entities at all. If the system owns a contiguous array of components, it can just iterate over them.

Of course there must be some processing involving multiple components of the same entity (e.g. draw what's specified by the Graphical component at the location and orientation taken from the Kinematic component), or each component becomes a degenerate single-component entity.

Both iterating over one type of component and over a set of potentially relevant entities with efficient lookup of the respective components need to be supported.

Omae Wa Mou Shindeiru

It seems to be a common pattern in ECS designs to b able to fetch a sibling component by type, so even if the outer loop is all X's, you can fetch paired Y's inside it, e.g.
foreach( g in graphics ) g.DrawAt(g.Parent.Child<Kinematic>());


However, I really hate the "update all the things" (anti)pattern - for each entity, update / for each system, update / for each component, update / etc..
It hides the actual data flow, hides dependencies, makes component connections implicit instead of explicit and promotes spaghetti.
The main update sequence of the game loop should be written in an explicit procedural or functional style.

You can setup each system with a list of entities who are populated automatically when you add/remove components from an entity. Each system may have a fixed list of required component types and a list of optional component types which determines if the system is interested in the entity or not.

This way you just have to iterate over this entities and process it in the system. Also this ensures that all required components do exists in the entity - so you can simply assert the pointers.

This is very efficient for cases when you dont remove/add entities on systems too often at runtime.

A few years ago i have successfully implemented this behavior in a java application, if you are interested i can look for the source (I may have it lying around somewhere).

Thank you everyone for the great input! I wrote a small prototype a few days ago and I published it on GitHub (https://github.com/michaeleggers/Entity_Component_System) so you can have a look at it, if you want to. I used the solution I posted in my initial post (link). What I do differently is that I register the Systems at a singleton called the Manager. I use the observer pattern to notify all systems when an entity gets a component attached or removed. Not all of this is implemented yet. The main problem now is that although the systems now know what entities they have to operate on (each systems keeps a list of entity IDs) does not mean they know can operate on their components. Also, I am not sure if the user should be able to edit the data in a component directly or if ONLY the systems should have permission to change state in the components.

I looked over your code and I have a few suggestions / comments.

What purpose does making Manager a singleton? That choice effectively implies your World is a singleton and to me that imposes an unnecessary design restriction that serves no purpose. It's not uncommon to manage different simultaneous simulations, particularly in game editors.

As an editor example, you have a surface where you render your game world simulation where you're editing the level, one where you render the game world in play-mode, and others where you render things like a material editor or some compositor node hierarchy. You might actually have different levels loaded all being rendered separately, all which require their own World instance. In all these situations, you may also have different systems at play and thus each World simulation should be tied to a specific finite list of applicable systems. A generalized class like Manager to me seems like an unnecessary abstraction, one which a World can fill easily.

Also somewhat related, you have several methods on Manager which seem ill-placed like create_entity, add_velocity, and add_position2D. I would probably suggest something like a ComponentFactory and possibly specializations for each component-type that you interact with to create your components. The allocation/destruction of entities would be a function of your World or some associated Scene object that your world has a reference to.

In the end, this notion of Manager goes away and it leaves you with a World where you might actually register the systems with instead. If you truly want to avoid having to register systems with each constructed World, you could use the factory pattern again:


class WorldFactory {
  typedef std::vector<System*> SystemVector;
  SystemVector systems_;
public:
  //! Register a system with the WorldFactory
  void registerSystem(System* system);

  //! Creates a world, adding each registered system to the World's simulation list.
  World* createWorld();
}

I still disagree to a degree because I believe each World should be constructed with its own necessary ticked systems and nothing which is unnecessary, but if you at least want something generalized, this approach at least provides an flexible and useful design pattern instead of the Manager singleton you had. You decide based on your need whether you create and reuse the same WorldFactory or if you create multiple instances as needed.

The main problem now is that although the systems now know what entities they have to operate on (each systems keeps a list of entity IDs) does not mean they know can operate on their components.

Why not?

Lets take a system that renders a sprite at a specific position. Such a system checks the entity when the "OnEntityAdded()" callback is fired and looks to see if that entity has a sprite and transform component. If it does, it adds it to that internal list and if not, it isn't added. It's assumed at this point that entity has both components. Then when the "OnEntityRemoved" callback is fired, the system simply removes that entity from any internal lists it maintains because the entity is being removed from the simulation.

Just remember that a system doesn't necessarily imply a 1-to-1 relationship to a component. There are definitely use cases where different component types (where applicable) are processed by the same system. For example, my RenderSystem knows how to draw 2D sprites and 3D meshes. While the components for these are different, the same system operates on these. So internally, that system maintains multiple lists and just handles updating each list accordingly during that system's update tick.

I am not sure if the user should be able to edit the data in a component directly or if ONLY the systems should have permission to change state in the components.

I personally advocate that your components represent the user interface into the underlying framework. The systems may expose various means for other systems to interact with one another but generally I would say that from a game designer perspective, the component's attributes are their path into influencing behavior.

The author talks about cache coherency.

when using ECS to optimize update, the ideal situation is to have contiguous arrays of components in the data cache.

Also, in this implementation every system (which is basically just a function) iterates over ALL entities

ideally you want to iterate just once over each array of componenet types

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

This topic is closed to new replies.

Advertisement