We've built an entity-component architecture that works ok for our needs, but it has something that bugs me a bit from a software engineering point of view.
std::weak_ptr for the
Entity owns the component through an
std::shared_ptr, while the
ComponentManager and other
Components refer to the component through a non-owning
The issue is that the components are not actually shared, and they should not be shared either. They're owned by a single entity. Having an
std::shared_ptr there suggests that anyone can take a copy of the
shared_ptr and own it too.
Here is a diagram of how the classes are organized:
- real owner of the components through
- does not know which components it holds
- we call
ComponentManager, which in turn calls
update()on every component it knows about
- there is one instance per type of component; we've done it like this to have control over which components get updated first (e.g.
CmpMatrixTransform, and from which the
CmpGfxis then updated)
- unofficial owners of the components through
weak_ptrs; it's "unofficial" because it's through them that the components are updated
weak_ptrs are stored in a
- once the (single)
shared_ptrgoes out of scope (e.g. when the entity gets deleted), a custom deleter tells the ComponentManager to remove the
vector(this also adds confusion to this architecture)
Component and derived:
- holds the core of the information and performs the main operations of the component
- can reference other components through
weak_ptr(hooked up at initialization, for now)
I strongly believe in using the right tool for the job, and although this architecture works, I'm curious to see if there are alternatives that would remove the confusion introduced by the shared_ptrs.
Maybe this is pertinent:
- The amount of entities and components is relatively low, so we won't gain much by making efforts to keep them close together (the rendering and the physics simulation are taking most of our frame time).
- We use this approach because of the re-usability offered by the components and entities from project to project.
- The project is single-threaded.
- The action takes place in the
Component, not in the
ComponentManager(i.e. it's a entity-component architecture, not an entity-component-system archiecture), so the
Componentneeds access to other
Components if they still exist, and these can be removed at any time.
I could use a kind of handle system through the
ComponentManager and query the appropriate one every time I need an access to a
Component, but this adds a dependency... (Maybe that's the price to pay..?!)
Do I have other options?