leudz / shipyard

Entity Component System focused on usability and flexibility.
Other
755 stars 46 forks source link

Question about EntityId management #187

Closed SeokshinSon closed 9 months ago

SeokshinSon commented 1 year ago
fn systemA(entities: EntitiesViewMut) {
    entities.add_entity(&mut MyComponent, MyComponent()); // first entity (e.g., EId(11703.3))
    entities.add_entity(&mut MyComponent, MyComponent()); // second entity (e.g., EId(11693.4))
}

fn systemB(my_components: View<MyComponent>) {
    my_components
        .inserted()
        .iter()
        .with_id()
        .sorted_by(|(a, _), (b, _)| a.index().cmp(&b.index())) // to make iterate first add_entity first
        .for_each(|e| println!("{:?}", e));
}

I want to iterate components first entity and then second entity. I suppose that second entity's index is always greater than first one, but that was not true. so above sorted_by is not work. Is there any way to iterate entity(by tracking) as same order of add_entity?

leudz commented 1 year ago

As you noticed indices are not always in increasing order. That's because they are re-used when entities are deleted. For example your first entity had 2 other entities at that index before.

There are no built-in way to get the order you want. In theory you could kind-of use the timestamp when they are inserted but since they are added in the same system that wouldn't work.

80ROkWOC4j commented 11 months ago

I'm confused about the answer to your question, so I'll ask just to be sure. My understanding of ECS is that components should be traversed in index order. This seems to be the case based on the implementation of Iterator's next() function. And since Shipyard recycles EntityId by gen bit, the EntityId (gen bit + index) will not always be incremented sequentially, but as long as no Entity deletion occurs, the iterator will increment sequentially, i.e. it will eventually iterate in the order they are in memory (in order of EntityId's index bit)?

leudz commented 11 months ago

My understanding of ECS is that components should be traversed in index order

For the very simple implementation that's true, probably for bit set also but not for sparse set or archetype based ECS.

In shipyard the iteration is based on the order of components in the data array (and dense, they have the same order) of the storage with the least components. This order depends on insertion and deletion order. In fact when it comes to single storage iteration the index array is not accessed at all.

Like SeokshinSon, you can also sort the storage to force a specific ordering.