0

I'm trying to implement a component based design for a game I'm making. I decided to write it in C++, but I'm not very good at it. Coming from a Java background I encountered a problem when trying to manage the std::vector for the components. Right now each entity has a vector of components that can be of different derived classes such as "Transform Component" which has an x and y field that I will access later. From what I've read I have to use a std::shared_ptr for each component, and that has worked fine except when I retrieve a component and try to cast it I start getting errors.

The code looks like this:

Component.hpp

class Component
{
public:
    virtual ComponentType getType() = 0;

    virtual ~Component() { }
};

Transfrom.hpp

class Transform : public Component
{
public:
    float x, y;

    virtual ComponentType getType() { return ComponentType::TRANSFORM; }
};

Entity.hpp

class Entity
{
public:
    Entity() : m_components() { }

    Component& getComponent(ComponentType type);
    void addComponent(std::shared_ptr<Component> comp);
    bool hasComponent(ComponentType type);

private:
    std::vector<std::shared_ptr<Component>> m_components;
};

And when I try to use it:

// This gives an error!
Transform comp = std::dynamic_pointer_cast<Transform>(entity.getComponent(ComponentType::TRANSFORM));

How can I fix this?

Belfer4
  • 113
  • 5

2 Answers2

0

std::dynamic_pointer_cast<Transform> doesn't return a Transform, it returns a std::shared_ptr<Transform> so your cast should look something like:

std::shared_ptr<Transform> comp = std::dynamic_pointer_cast<Transform>(entity.getComponent(ComponentType::TRANSFORM));

Also, if the compiler can statically deduce the type of your r-value you could just use the auto keyword:

auto comp = std::dynamic_pointer_cast<Transform>(entity.getComponent(ComponentType::TRANSFORM));
-1

Your implementation is a bit off of the other Entity-Component systems I've seen. I recommend taking a look at EntityX. It should give a good idea of what a working implementation looks like.

You could also read these which may help:

Role of systems in entity systems architecture

Component - Game Programming Patterns

Understanding Component-Entity-Systems

As for some specific code critiques:

  • Using templates to manage your component types, not an enum. This will make for cleaner code. I'd only use an enum (or any numerical type or string) if you were implementing scripting or any runtime-based component system, but that's a whole different issue. Templates just offer better type safety.
  • Using std::unique_ptr instead of std::shared_ptr. If you're making copies of entites for whatever reason, you don't want them to share a pointer to the same component. If you're not copying them, you're wasting performance.
  • Using an ID for an entity and a central system (that holds components tied to a specific ID) instead of Entity objects that hold the components themselves.
LiquidFeline
  • 1,381
  • 1
  • 13
  • 31
  • Thanks for pointing me in the right direction I was actually a bit confused as the difference between component based and entity-component based. Just an inquiry on the critiques, I'm not much of an expert on templates but could you direct me on how I could use them for the component types? – Belfer4 Jul 29 '15 at 15:26
  • Take a look at EntityX's source code for a working example it. I haven't taken a full look at it, but I've tried it before and it uses template types. There are a few ways to do it, but with typeid you could do something like this: template<typename T> hasComponent() { for (auto comp : components) if (typeid(comp)) == typeid(T) return true; return false; } so you could simply do: if (entity_manager.doesEntityHaveComponent<SomeComponent>(id)) { .... }'. – LiquidFeline Jul 29 '15 at 15:55
  • I recommend researching and learning how to use RTTI. It should make understanding how to use templates for component identification much easier. – LiquidFeline Jul 29 '15 at 16:00