You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I use a "lifetime" component to handle entity's removing. This is pretty easy, as I can iterate all entities with "Lifetime" component and check if lifetime is still valid, otherwise delete entity.
I want to have the same for components. Some components should only live for "x" seconds.
Do you have any idea how to implement this?
I first thought of a lazy_exec with time delay (just removing comp from entity). The solution should be similar to lazy Update, some "Read" resource which can be written in parallel.
I do not want to iterate over all components.
I do not want a lifetime field in every component.
If you want to avoid per-tick iteration, I'd recommend something like an event system that sits outside the ECS (or in an ECS resource) that uses a binary heap.
Entity IDs get inserted in an ordering consistent with the time at which they should be deleted. Every tick, you'd just have a system that pulls items out of the binary heap while they refer to entities that need destroying on that tick. When the next item in the heap does not need destroying on that tick, you know that no others in the heap do either (because they have a total ordering). This significantly reduces the overhead of checking for this sort of deletion.
The disadvantage is that it's quite hard to modify the lifetime of an entity on the fly. If you want that, I recommend using something like an LRU-style heap or one that allows reprioritising elements.
If you want to avoid per-tick iteration, I'd recommend something like an event system that sits outside the ECS (or in an ECS resource) that uses a binary heap.
Entity IDs get inserted in an ordering consistent with the time at which they should be deleted. Every tick, you'd just have a system that pulls items out of the binary heap while they refer to entities that need destroying on that tick. When the next item in the heap does not need destroying on that tick, you know that no others in the heap do either (because they have a total ordering). This significantly reduces the overhead of checking for this sort of deletion.
The disadvantage is that it's quite hard to modify the lifetime of an entity on the fly. If you want that, I recommend using something like an LRU-style heap or one that allows reprioritising elements.
It's fine for me to iterate all lifetime entities, there aren't so many. My problem comes with lifetime for components.
I want to add any component, and remove hat after "x" seconds.
It's fine for me to iterate all lifetime entities, there aren't so many. My problem comes with lifetime for components.
I want to remove to add any component, and remove hat after "x" seconds.
In that case, just iterate over the join of entities and lifetimes and decrement some counter in the component each tick, until it hits 0
Then perhaps a component like struct Lifetime<C: Component>(u32, PhantomData<C>);? Then you can create a system that does this that is generic over C and insert it into the system dispatcher for every component you want to do this for.
What about adding the end-time to the component as a field, so that it's "slow until". You can check that field when you iterate over the slow entities and remove the component if the contained time passed.
Adding a single new Component A, adds overhead for Animation<A> & Lifetime<A>, and even worse: Lifetime<Animation<A>>...
I think it's worth mentioning that Lifetime<A> will only be added overhead if you actually use it. If you never mention that type then Specs will never know or care about it because of monomorphization - Lifetime<A> is a completely different, unknown type, even if you use Lifetime<Slow>.
Making Lifetime generic is honestly the best solution I can see to this problem. It acts as the field that you would otherwise have to add to every component individually, and so fits the intended use of an ECS.
Activity
zesterer commentedon Dec 12, 2020
If you want to avoid per-tick iteration, I'd recommend something like an event system that sits outside the ECS (or in an ECS resource) that uses a binary heap.
Entity IDs get inserted in an ordering consistent with the time at which they should be deleted. Every tick, you'd just have a system that pulls items out of the binary heap while they refer to entities that need destroying on that tick. When the next item in the heap does not need destroying on that tick, you know that no others in the heap do either (because they have a total ordering). This significantly reduces the overhead of checking for this sort of deletion.
The disadvantage is that it's quite hard to modify the lifetime of an entity on the fly. If you want that, I recommend using something like an LRU-style heap or one that allows reprioritising elements.
philipp-kaiser commentedon Dec 12, 2020
It's fine for me to iterate all lifetime entities, there aren't so many. My problem comes with lifetime for components.
I want to add any component, and remove hat after "x" seconds.
zesterer commentedon Dec 12, 2020
In that case, just iterate over the join of entities and lifetimes and decrement some counter in the component each tick, until it hits 0
philipp-kaiser commentedon Dec 12, 2020
We are talking about different things. I do not want to remove an entity with a lifetime component. It's absolutely clear to me how to do that.
I want to remove a component:
In this case, not the entity gets a lifetime component, but the component has a lifetime itself.
I want to add lifetimes to any component.
zesterer commentedon Dec 12, 2020
Then perhaps a component like
struct Lifetime<C: Component>(u32, PhantomData<C>);? Then you can create a system that does this that is generic overCand insert it into the system dispatcher for every component you want to do this for.philipp-kaiser commentedon Dec 12, 2020
Now you got me right :)
Yes, I already thought about this. Although this would duplicate all components (which have a lifetime).
I'm currently doing my animations this way:
Adding a single new Component
A, adds overhead forAnimation<A>&Lifetime<A>, and even worse:Lifetime<Animation<A>>...Is this the way to go?
I hoped for a more generic way:
zesterer commentedon Dec 12, 2020
I don't think you can avoid that overhead unless you build an event system outside the ECS.
minecrawler commentedon Dec 13, 2020
What about adding the end-time to the component as a field, so that it's "slow until". You can check that field when you iterate over the slow entities and remove the component if the contained time passed.
philipp-kaiser commentedon Dec 14, 2020
That's exactly the question. Should one add this per component as a field, or is there a generic solution to this "lifetime for components" problem.
(Of course it's always better to not decrease or increase per tick, but only check if "dead time" is reached)
LoganDark commentedon Feb 21, 2021
I think it's worth mentioning that
Lifetime<A>will only be added overhead if you actually use it. If you never mention that type then Specs will never know or care about it because of monomorphization -Lifetime<A>is a completely different, unknown type, even if you useLifetime<Slow>.Making
Lifetimegeneric is honestly the best solution I can see to this problem. It acts as the field that you would otherwise have to add to every component individually, and so fits the intended use of an ECS.