I\'ve been experimenting with making a component based system similar to Unity\'s, but in C++. I\'m wondering how the GetComponent() method that Unity implement
Apologies if this is not what you are looking for, but I had an idea to use the unordered map with a type index and, with the help of some metaprogramming and TR2, place multiple pointers to the component into the map, including its direct base classes as additional keys. So getComponent and getComponent along with a down-cast will have the same pointee.
#include
#include
#include
#include
#include
class Component {
public:
virtual ~Component() {}
};
class GameObject {
public:
template
void addComponent(T *component);
template
T *getComponent();
std::unordered_map components;
};
template
struct direct_bases_as_tuple {};
template
struct direct_bases_as_tuple> {
typedef std::tuple type;
};
template
struct AddComponent {
GameObject *owner;
explicit AddComponent(GameObject *owner) : owner(owner) {}
void operator()(ComponentType *component) {
AddComponent{owner}(component);
using BaseType = std::tuple_element::type;
owner->components[typeid(BaseType)] = component;
}
};
template
struct AddComponent<0u, ComponentBases, ComponentType> {
GameObject *owner;
explicit AddComponent(GameObject *owner) : owner(owner) {}
void operator()(ComponentType *component) {
return;
}
};
template
void GameObject::addComponent(T *component) {
using ComponentBases = direct_bases_as_tuple::type>::type;
constexpr classCount = std::tuple_size::value;
AddComponent{this}(component);
components[typeid(T)] = component;
}
template
T * GameObject::getComponent() {
auto iter = components.find(typeid(T));
if (iter != std::end(components)) {
return dynamic_cast(iter->second);
}
return nullptr;
}
class Collider : public Component {};
class SphereCollider : public Collider {};
int main() {
GameObject gameObject;
gameObject.addComponent(new SphereCollider);
//get by derived class
SphereCollider *sphereColliderA = gameObject.getComponent();
//get by subclass
SphereCollider *sphereColliderB = dynamic_cast(
gameObject.getComponent()
);
if (sphereColliderA == sphereColliderB) {
std::cout << "good" << std::endl;
}
}
I created the AddComponent struct to recurse through the component base classes at compile-time and insert the pointer (value) with the corresponding class (key) each iteration. The helper struct direct_bases_as_tuple was inspired by Andy Prowl's answer to change the direct bases into a tuple. I compiled this using GCC 4.9.2 using C++11 features.