I have implemented an entity component sytsem (ECS) in my game engine (SFML and C++ 17). An entity has an array of components. You can get a components by its type e.g.: myEntity.GetComponent<RenderComponent>()
. So far so good.
The problem
Best to illustrate this point by an (admittedly oversimplified) example:
Some systems or possibly other components might want to be able to call myEntity.GetComponent<RenderComponent>()
without knowing the type of that render component (e.g. whether it is a house render component with a sprite and a paritcle system for smoke or a character) but knowing that every render component has e.g. a GetPixelMask()
method.
A more concrete case of this is the collision component that might be implemented as a collision box or a pixel mask that may come from any type of render component. However, every collision component would have a method bool Contains(Position)
. I would like to be able to loop through all entities with a collition component and check whether e.g. the mouse click lies within them.
I want a clean solution. It must not use polymorphism, it should solve the problem in a neat way.
Possible Solutions
This is bad code smell to me but still its a solution. Screw polymorphic behaivour and just add an if cause to the systems. Something like
If(myEntity.HasComponent<HouseRenderComponent>()) { /*Call method a*/ }
andIf(myEntity.HasComponent<CharacterRenderComponent>()) { /*Also call method a*/ }
Another solution would be to make it so that the component are 'configured'. This is my current solution which kinda works but isn't all to clean (I find). This would mean making some
RenderObject
base class and letting theRenderComponent
manage a dictionary ofRenderObject
pointers.RenderObject
s would have to be added through a method like AddRenderObject() and accessed through an id which isn't all too efficient (Not my biggest concirn here). However, everyRenderComponent
would have the same methods and the specific type of theRenderComponent
would be defined through theRenderObject
s added.
Question
I'm pretty sure that adding some kind of real polymorphism to the components would be possible and I could figure out how to do it. The question is: is that good design? - as for me it kind of defeats the point of the ECS. I'd be grateful if you could share your experiences and how you have dealt with this. I can't be the first one to have come across this problem!
Thanks for your help!