Thank you everyone for your answers!
@Zakwayda What do you mean "what I posted won't necessarily reside on the stack"? Aren't arrays local and therefore created on the stack? (Unless one creates a dynamic one with ptr = new Component[N])
Regarding the instantiation of components, you would suggest for something like
struct {
vector<TransformComp> transforms;
vector<ColliderComp> colliders;
vector<SpriteComp> sprites;
...
} components
where all components are created (as defaults) just once at the beginning (and new ones are created whenever the vectors expand), and I then reference to them for "populating" an Entity? (Meaning, an entity is something like a list of indexes that refer to which components belong to that entity, and instantiating an entity just means instantiating this list, without any creation of new components, and maybe setting some members of its components, since the default ones may not work).
For the third point, yes, I was pondering about what to go for: simple arrays? pointers? vectors? (smart) pointers to vectors? other collections, like std::array?)
@DixiE Thank you for the comprehensive snippet! I am not very familiar with Rust. I had a look at the library and at the conf transcript, but I haven't been fully able to grok the contents. What seemed interesting in the conference transcript was the Generational Indexing. To me, it seemed a way to solve the "need for instantiation of new components" problem, since it's a way of marking unused components so that they are reused later for new entities (correct me if I'm wrong). I'll have to read everything again, because I am not sure I got any idea on how to solve the "not all entities use all components" problem (which is about addressing the inefficiencies due to allocating N components of all types at the beginning).
Any reference for C++ on these topics?
@Shaarigan Nice! What data structure do you use for the first point? (To keep all components of one kind, and expanding the collection in a thread-safe way. By the way, do you create N new components when you have the need for expanding one of those collections? Or do you just allocate additional memory and copy all old components to the new buffer, and then create components when you need them?)
What do you mean with " This way we keep the performance impact on adding new component instances of a type to an entity instead of where the systems aquire them" ? I'm not sure I understand.
Your technique (with entities that are just masks for which components they use) is similar to the ECS implementation described here:
is it? Or is it much different?
What do you mean exactly by "collecting entities before they are processed"? That you do something like:
// running update for system S
relevant_entities = vector
for entity in entities {
if entity.mask matched S.mask
relevant_entities.push(entity)
}
for relevant_entity in relevant_entities {
// do stuff on relevant_entity's components that are important for S
}
instead of just looping once over all entities and updating their components if their mask matches the system's mask? (I.e. everything in one loop instead of 2 loops, one for "filtering entities" and one for updating components).
Interesting addition the one about locks and systems updating components in parallel! Any reference for that? (For ECS with parallel systems).
@Dawoodoz I am sorry I did not understand a single word of you answer. Is it supposed to be an answer to this thread? Please don't take that as an offense, it is probably me not understanding what you said because it was too complicated for me! (Just starting out)