🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Questions about Pure ECS (Entity Component System) and update systems

Started by
3 comments, last by wintertime 3 years, 7 months ago

I have written an ECS but I have some questions about the update phase. (in systems) I have read many articles, but not found references to this sort of problems.

In order to have benefits from ECS (cache friendly, for example), they are the following requirements:

  • Entity must be just an ID.
  • Components must be only pure data (struct with no logic).
  • Systems contains the logic and update the components.
  • No interactions between systems (instead systems communicate by adding “Tag” components to entities).

So, the logic applied in each system is fine and all works when they are no “user code”. But, when we deal with user code (for example the user can attach C++ code to an object (like Unity, Unreal)), the problems come:

  1. Since, components contain only the data, when the user modify the local position, the world position is not updated (the world position will be computed when the Transform System will process each Transform Component. So if the user asks for the world position after modifying its local position, it will get the previous world position and not the actual.
  2. When an entity is removed, its children must be removed. Since the component contains only the data and not logic, the children will not be removed (it will be on the next Parent System update). So we have some “delay” (the children will still be accessible but will be removed on the next Parent System update).
  3. Supposing we have the entities A, B, C. B is a child of A. In the user code (c++ code attached to the entity), the user set the parent of B has C, then remove entity A. When the Parent System will update, it will detect that A has been removed, (it can also detect that the parent of Entity A has changed) but how the system can know if the entity A has been removed after the parent change of Entity B or before?

Adding logic into components will ruins advantage of pure ECS (doing the same actions on all same components, in a cache friendly way), so IMHO it's not a solution.

Anyone have the solution? I would like to know how are you deals with this sort of problems with your ECS implementation.

Thanks!

Advertisement

v3n0m2412 said:
In order to have benefits from ECS (cache friendly, for example), they are the following requirements: Entity must be just an ID. Components must be only pure data (struct with no logic). Systems contains the logic and update the components. No interactions between systems (instead systems communicate by adding “Tag” components to entities).

None of those things have anything to do with being cache friendly. You get cache friendliness by looking at access patterns; at the order that parts of memory are touched by the code, often addressed by having things that you read or write around the same time be next to one another in memory. Pure ECS doesn't necessarily get you that, on its own. The “no interactions between systems” seems particularly perplexing to me on that front, because then you're using more memory (that has to be cached). Have you actually got profiling data that shows doing that is faster?

If you want your code to take cache utilization into account, then you should start with the data you actually have and its relationships, not with some rigid and dogmatic/"pure" ideal of how you think it's supposed to be laid out. You won't magically solve cache performance problems by using ECS. In fact, it's possible that you could make them worse! If you care about perf there are no one-size-fits-all solutions.

What is the actual data that you have and what are the exact things that you need to do with it?

v3n0m2412 said:
Adding logic into components will ruins advantage of pure ECS (doing the same actions on all same components, in a cache friendly way)

How so? Putting more functions on a class won't make it bigger, unless you're using JavaScript or another dynamic language where objects are tables and both methods and fields are entries in those tables. Is that the case for you? In fact, can you give more context here? What language and framework/API/platform are you using?

v3n0m2412 said:
Since, components contain only the data, when the user modify the local position, the world position is not updated (the world position will be computed when the Transform System will process each Transform Component. So if the user asks for the world position after modifying its local position, it will get the previous world position and not the actual.

Why only update the transforms there? Aren't the local and world positions in the same place?

v3n0m2412 said:
When an entity is removed, its children must be removed. Since the component contains only the data and not logic, the children will not be removed (it will be on the next Parent System update). So we have some “delay” (the children will still be accessible but will be removed on the next Parent System update).

You could delay ALL actual deletions to the next frame and clean them all up at once.

v3n0m2412 said:
Supposing we have the entities A, B, C. B is a child of A. In the user code (c++ code attached to the entity), the user set the parent of B has C, then remove entity A. When the Parent System will update, it will detect that A has been removed, (it can also detect that the parent of Entity A has changed) but how the system can know if the entity A has been removed after the parent change of Entity B or before?

Could update the parenting system before whatever removes the entities for real?

But this does kind of show the limitations of trying to stuff things into the ECS box that maybe don't really belong there.

I think, the problem stems from attaching the user code to the entity (object). In ECS you are supposed to have logic in the systems instead, so you should have the user create some new component and have corresponding code for the system from the user.

So now you have, for your example, that attachment component and let the user code in attachment system figure out how to switch the attachments.

For the other example of moving local position, there might be a way to attach a script to the movement system, which takes care to update the world position afterwards.

This topic is closed to new replies.

Advertisement