Quillraven / Fleks

Fast, lightweight, multi-platform entity component system in Kotlin
MIT License
174 stars 19 forks source link

Safe way to reference entities? #113

Closed dragbone closed 12 months ago

dragbone commented 1 year ago

I'm working on a game prototype using fleks and I'm struggling to find a good way to reference an entity from a component. A simple example would be one entity following another entity and therefore needing a reference. It seems that the Entity value class is not a safe reference because entities get reused after removal from the world, so a reference might reference a completely different entity in the future. Is there some safe way to reference entities? Do I need to set a remove entity hook and search for all components that might reference that entity?

Quillraven commented 1 year ago

Hi,

this is a good question and tbh I don't know what are the best practices here.

I remember that I did what you mention at the end in an old project using Ashley and I didn't like it because every time I add a component with entity references I had to remember to add the cleanup logic to the hook. Also performance wise it is not ideal because you have to iterate through all such components and also through the entity ref containers.

Another solution which is maybe better and which I also used in some projects is a RemoveSystem with a RemoveComponent. Instead of removing an entity directly you then have to add a RemoveComponent to it. The system then really removes the entity. This has the advantage that you can control when entities get really removed. It is also easy to e.g. add a timer to en entity and remove it delayed by simply adding a delay to the RemoveComponent and adjust the logic in the RemoveSystem.

Also, on your entity ref components and their system you can then check if your entity has a RemoveComponent and remove it or do whatever logic you need to do (e.g. follow another nearby entity).

Finally, in the last version of Fleks you can provide your own EntityProvider. Check the wiki. That way you can remove the recycle logic and always create new IDs. But be careful to not overflow the IDs.

Of course I am open for other ideas and can add some generic solution to Fleks if there is a good one 😃

dragbone commented 1 year ago

Finally, in the last version of Fleks you can provide your own EntityProvider. Check the wiki. That way you can remove the recycle logic and always create new IDs. But be careful to not overflow the IDs.

That actually sparked an idea! What I want is to identify different versions of the same entity, so I hacked together some utilities to actually track versions of entities: https://gist.github.com/dragbone/149b63c55eec650a32bf60d697b80fc0

A generic solution could probably work pretty similar by tracking versions internally and providing references when needed (without attaching a Component to every entity).

Quillraven commented 1 year ago

Is this a convenient enough solution for you? Looks pretty minimalistic and nice.

Out of curisoity: would it help if recycled entities don't get reused within a single frame (=world.update call)? I think that should also work at least if the important systems are triggered every frame. If you have systems that run at a fixed rate then this won't help. In that scenario your solution is better and should still work.

I personally don't want to add this directly to the current "core" of Fleks because this problem does not occur in every game and I guess it has some impact on the performance as well (most likely not huge though).

I am thinking more towards a second EntityProvider implementation that contains the entity versioning logic. It can then be set by users like a normal EntityProvider but it already comes with Fleks.

edit: I just googled a little bit and seems like the entity versioning approach is a good practice. Some ECS have it built-in into the entity. The entity is no longer just an id. It is the combination of id + version. The version simply gets incremented when the entity gets reused.

Again, I personally would like to keep the entity as a simple ID because that should be the fastest way to do things but I will give it a try what kind of impact it will have, if we make entity a normal data class by simply running the benchmarks and compare the results.

If you have time and if you are motivated, feel free to help me out and create a PR because I am not sure when I will have time to add this :( You will be then mentioned of course in the next release's changelog and your internet fame will increase tremendously!

dragbone commented 1 year ago

If you have time and if you are motivated, feel free to help me out and create a PR because I am not sure when I will have time to add this

I haven't looked much into the inner workings of fleks but I'll give it a try :)

Quillraven commented 12 months ago

Snapshot release should be live in the next few hours. Stable 2.5 release will be ready in the next few weeks