Domanda

I am making the engine for a game and I can't seem to solve the following problem.

So, I have a base component class from which all the different components are derived. A GameObject is basically a container for different components. The components are stored in a vector containing pointers to the base component class. Now I need the GameObject class to have a getComponent member function template that will return the component with the requested type from the vector.

To be more clear:

class Component 
{
        /..../
};

class RigidBody : Component
{
        /..../
};

class Animation : Component
{
        /..../
};

class GameObject
{
public:
        template <class T>
        T* getComponent();

        void addComponent(Component*);
private:
        std::vector<Component*> m_components;
};

/...../

GameObject test;
test.AddComponent(new RigidBody());
test.AddComponent(new Animation());
Animation * animation = test.getComponent<Animation>();

Or something among those lines.

For simplicity's sake say that the vector is guaranteed to have the component that we are looking for and that there are no components of the same type.

Since the pointers in the vector are of the base component type, how can I check if they originally were of the requested type? Thanks in advance!

È stato utile?

Soluzione

Assuming that Component has at least one virtual function (otherwise what's the point of inheriting from it, right?) you should be able to do what you need using Runtime Type Information (RTTI) and dynamic_cast, like this:

template <class T> T* getFirstComponent() {
    for (int i = 0 ; i != m_components.size() ; i++) {
        T *candidate = dynamic_cast<T*>(m_components[i]);
        if (candidate) {
            return candidate;
        }
    }
    return nullptr;
}

Recall that dynamic_cast<T*> would return a non-null value only when the cast has been successful. The code above goes through all pointers, and picks the first one for which dynamic_cast<T*> succeeds.

Important note: While this should do the trick at making your program do what you want, consider changing your design: rather than pulling out objects by type, give them virtual functions that would let you use them all in a uniform way. It is pointless to put objects of different classes into one container, only to pull them apart at some later time. RTTI should be used as the last resort, not as a mainstream tool, because it makes your program harder to understand.

Another valid approach would be to store the individual components separately, not in a single vector, and get the vector only when you need to treat the objects uniformly.

Less important note: if nullptr does not compile on your system, replace with return 0.

Altri suggerimenti

There are occasions where a system would want to group derived types from a base class vector, for example, the optimisation of multithreading.

One system I cooked up uses polymorphism to create a user defined type to avoid typeid or derived_class, here is some pseudo code...

class BaseType {
public:
virtual int getType() = 0;
}

class ThisType : public BaseType {
public:
int getType() {return 1;};
}

class TypeMaster {
private:
std::vector<ThisType*> myObjects;
public:
void add(ThisType* bc){ myObjects.push_back(bc); };
}

std::map<int,TypeMaster*> masters;
std::vector<BaseType*> objects;

for(int i=0;i<objects.size();i++){
masters.find(objects[i].getType())->second.add(objects[i]);
}

You would have to do a bit of work to make a system but the rudements are there to convey the idea. This code processes an arbitary vector of base objects and appends them to the vector of its type master.

My example has a collection of execution pools with multiple instances of the type master meaning the type master cannot be polymorphed because in that scenario the object would not be able to move around execution pools.

Note the lack of use of typeid or derived class. For me, implementations using native types keeps it simple without importing bloating libraries or any unnecessary execution fuss. You could perform speed trials but I have always found simple native type implementations to be quite succinct.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top