Notifying systems of component state change

Started by
2 comments, last by DemonDar 7 years, 7 months ago

I'm working on a new game, and for this one I've decided to go with a more pure ECS design than my last one. In particular, Entities are represented with unique IDs, Components are POD structs with no inheritance requirements (though they must be default and copy-constructible), and Systems do not contain any non-reproducible state.

I think I should clarify the last bit, in my approach Systems may contain whatever intermediate data they need, as long as it can be reproduced from the state of the Entities and Components once the game is reloaded. For example, a CColliderComponent would only contain basic collision shape data, whereas the BulletPhysicsSystem would own the actual btCollisionShape objects that correspond to those components, and update them accordingly.

The problem I now face is that the BulletPhysicsSystem needs to know when new colliders have been created, destroyed, or when their shapes have been changed. To do that, I've decided to add a new element: 'Tags'. Tags are like components of components, though they are more representative of events. Unlike components, you can have multiple instances of the same type of tag on a single component, and they are not persistent. They only live to the end of the current frame, and then all tags are destroyed.

In such a system, when a CColliderComponent's is created, it is given the TNewComponent tag. When its shape is changed, it's given the TCollisionShapeChanged tag. When its destroyed, it is given the TDestroyedComponent tag, and then destroyed at the end of the frame. That way, the BulletPhysicsSystem can do a pass where it checks for specific tags on all components it understands, and updates its internal state accordingly, allowing components and tags to remain as simple POD structures.

I just came up with this idea a few hours ago and its more than likely that there may be some serious flaws with it, so I'm interested in hearing how any one here has managed to keep components as POD, while still updating things where necessary. I don't think the systems setting a field on a component should be responsible for knowing exactly everyone who cares about modifications to that field, so it seems that some sort of design for notifying the relevant systems would be useful.

Advertisement

I'm far from an engine expert, but as someone who has recently been studying the wiki article out of curiosity this struck me:

https://en.wikipedia.org/wiki/Entity_component_system#Inter_system_communication

Sounds like your tag system is an elaborate network of flags like described there. Perhaps look into the observer pattern it recommends?

I recently made a similar change, moving from entities having a list of pointers to all components so communication could be done through the entity object, to using plain integer ids to represent entities.

Regarding state changes, I decided to go for the event queue approach for communication. For example, the most common state change with entities will probably be their position as they move, so any entity that moves I send a 'move_object_event' including the new position (3 floats) and the entity id (int/long). As long as there isn't a crazy number of entities all moving at the same time, then this approach should be very efficient and keep your systems nice and decoupled from each other. There are a few caveats I noticed though :

- When you send an entity id, you need to find the component related to that entity. Currently, I am just doing a linear search of all components (obviously not efficient for large number of entities) but in the future I will have to do something better like some hash search. Either way, there is an extra cost here which means an extra cost for every component that needs to be updated

- In the naive form that I implemented my event queue, the events are only processed at the beginning of the next step. This leads to a one-step lag between systems updating with new positions. Normally this is not a problem at all if done consistently but perhaps can lead to some issues. One solution I guess is to have a hybrid event queue system, one that is processed at the beginning of the next step, one that is done more immediately.

Regarding the notifying of state-changes issue, I also have some state enum for various components (e.g. collision boxes) which when moved or rotated, are flagged as 'MOVING'. Since the collision system only needs to really check moving objects, it then creates a small list of moving components and checks those. Once the collision system has finished processing everything, the flags are reset to 'INACTIVE' in preparation for the next step. Like I said in the previous paragraph, in my engine this is currently done one frame later due to the event queue lag but is not necessarily a problem for me, but might be in other situations.

Anyway, I haven't fully solved all my problems with this approach but they are just my own thoughts and (intermediate) solutions. If you don't know about this book already, I'd take a look at http://gameprogrammingpatterns.com/ since it discusses a lot of these design issues from a pure design point of view (as opposed to throwing code at you).

You should look into Svelto ECS framework, it solves the problem by using a delegate stored in the component, the point is that delegates should be added by Systems and used by systems when Component is created so you don't have to serialize the event (serialization is usually the main stopper to having delegates in components). Carefully read blogposts of its author, there's a lot of deep though behind that framework and I still have to fully understand it, but starting right now to use it in my first game.

I wouldn't be suprised if all future ECS framworsk will inherit that feature from Svelto.

This topic is closed to new replies.

Advertisement