1
\$\begingroup\$

I've got component class:

class Component
{
public:
    Component();
    ...
};

then my various components derive from the base Component class

class VelocityCom : public Component
{
public:
    VelocityCom();
    ...
};

and then an entity class that holds the components and is able to return a specific component for manipulation

class Entity
{
public:
    Entity();
    std::unique_ptr<Component> getComponent(...);
private:
    std::vector<Component> components;
};

The problem that I'm having with this approach lies withing the act of getting a specific component. Let's say I want to get a pointer to the velocity component. I can't just have whateverEntity.getComponent(Types::Velocity); because the method returns a Component and not a VelocityCom. I thought about casting the Component pointer to a VelocityCom pointer but it seems that a lot of people don't like the idea of downcasting. So my question is what is a good way to get a specific component in an entity component system? Is downcasting okay in this situation or should I change my implementation to where I don't have to?

\$\endgroup\$
3
  • \$\begingroup\$ TBH, if you know that your component is of a certain type, downcast it and get on with it. As long as you do it statically and not dynamically :) The other way around is using stuff like what's in Unity/c#/Java where RTTI is available and well, part of the language. \$\endgroup\$
    – Vaillancourt
    Sep 18, 2015 at 4:09
  • \$\begingroup\$ If you don't want to cast, you can transfer your objects from being held by the entity to being held by a manager of that type of component. I have only tried a bit this method so I'm not sure how it goes on a 'serious/normal' project. \$\endgroup\$
    – Vaillancourt
    Sep 18, 2015 at 4:10
  • 1
    \$\begingroup\$ I would suggest you add the c++ tag to your question, as c++ is a bit different from c#/java w.r.t. RTTI availability and usage. \$\endgroup\$
    – Vaillancourt
    Sep 18, 2015 at 4:12

1 Answer 1

1
\$\begingroup\$

First, returning a unique_ptr makes no sense. In your design (which is not an ECS, btw) a unique_ptr expresses ownership. The entity owns the component. If you return a unique_ptr then the entity must necessarily give up its ownership of the component. You don't want that.

Second, just downcast. "A lot of people" can dislike it all they want, but they're wrong. It's perfectly valid when used in the appropriate circumstances. Just about every engine with a component model similar to yours end up with functions like these on their core game object type:

struct GameObject
{
  // get generic component based on generic type identifier
  Component* Get(std::type_index type);

  // get a specific component based on compile-time type
  template <class T> T* Get() { return static_cast<T*>(Get(typeid(T))); }
};
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .