I've been planning out an Entity-Component System in C++. My idea of it is most in line with the one described on this page of the entity systems wiki. To summarize, components are just structs of data, all code is in systems, and entities are just IDs shared by components.
The issue I'm having is mostly to do with how components are stored and accessed. My intent was to have a vector for each component type (which inherit a base Component
class). These vectors are then stored in an unordered map, with a ComponentType
(an enum) as the key. An EntityManager
handles interactions with the vector, with functions like removeComponent
, which takes a ComponentType and ID as arguments (which would search the unordered map and then iterate over the matching vector until finding the correct component to remove).
I specifically liked this implementation because it meant I could add new component types without having to change the way the manager accesses the vectors.
I realized that this implementation only works when utilizing polymorphism (i.e., a bunch of vector<Component*>
s), since this allows them to all be stored in a single container, and operated on the same way. Unfortunately, this design results in the actual object data being scattered all over memory (even though the pointers are contiguous).
An advantage of the original structure that I chose, in my mind, was the improved cache performance offered by accessing large contiguous structures of data. But storing components in vectors is a problem, because then each vector is of a different type (ex: vector<Position>
vs vector<Velocity>
). This means I can't store them in one container, or use the same interface for operations on all of them. I believe I'd have to add new code to handle each new type of vector every time one was added.
I've been wracking my mind for the last few hours trying to devise a compromise. I can't seem to think of a design that would both store each type of component contiguously in data as well as allow for generic operations on those collections (ex: functions like the aforementioned removeComponent
that don't require edits with each new compent type). I'm also unsure if my desire to maintain contiguity is reasonable, or if the impact on performance would actually be quite minor.