I am currently designing an Entity Component System (ECS) where each entity is of a unique type:
template <typename... ComponentTypes>
struct Entity
{
using Signature = std::tuple<ComponentTypes...>;
size_t ID;
};
This design decision has led to some unique challenges and I'm seeking advice on how to handle them.
- Non-contiguous Entity Storage: The main pitfall for me is that it's harder for the user to store the entities contiguously, because they would need a container for each component type variation.
- Order-Independent Component Types: The order of the Component types
doesn't matter. For example, component types:
["Position", "Health"]is the same as["Health", "Position"]. You can find the essence of how I did it here: Link. I am basically sorting the types at compile-time. - Archetype-Based Design: I'm using an archetype-based design. I am using a type-erased archetype object, which I need to cast to the respective type to access the components. Each archetype stores a sparse set of Entities, along with a tuple of vectors for the components.
- Accessing Archetypes: To access an archetype, you need to know the whole list of types the archetype stores. This is the main reason for the templated Entity.
- Strongly Typed Systems: Systems are strongly typed at compile time, which is similar to how ECST does it.
- Entity Type Change: Each time I add/remove a component, I need to change the type of the entity.
- Entity::Signature as Key: The
Entity::Signatureacts as a key to know in which Archetype type the Entity resides, which would be faster than looping over all the Entities and checking if the IDs are equal. - Heavy Template Metaprogramming: I am heavily relying on template metaprogramming. This provides type safety, as the compiler checks that the types used with a template are valid for the operations the template performs.
I am interested in hearing your thoughts on this design decision and any potential pitfalls or improvements you might suggest. Thank you in advance for your insights!