C ++ component architecture
I am having trouble figuring out how to create a component based architecture in C ++. But I can't figure out a way to combine a vector of components with a class that comes from the component.
I want to override the virtual function of the components. But the only way to make it call the overridden function is to make the component class a pointer, but I want every game object to contain its own components in a vector, not outside the class like a pointer.
I tried to remove as much unnecessary code as possible.
My structure:
//GameObject class, contains components and other objects
class GameObject
{
public:
GameObject(){}
~GameObject(){}
void AddChild(GameObject child)
{
children.push_back(child);
}
void AddComponent(Component component)
{
components.push_back(component);
}
void Input(){}
void Update(){}
void Render()
{
for(unsigned int i = 0; i < components.size(); i++)
components[i].Render();
}
private:
std::vector<GameObject> children;
std::vector<Component> components;
};
//base class component
class Component
{
public:
Component(){}
~Component(){}
virtual void Input(){}
virtual void Update(){}
virtual void Render(){ cout << "Component -> Render()" << endl; }
};
class MeshRenderer : public Component
{
public:
MeshRenderer(Mesh _mesh, Material _material)
{
mesh = _mesh;
material = _material
}
~MeshRenderer(){}
//override components virtual Render()
void Render(Transform transform)
{
mesh.Render(material);
cout << "MeshRenderer -> Render()" << endl;
}
private:
Mesh mesh;
Material material;
};
GameObject* root = new GameObject();
MeshRenderer meshRenderer(mesh, material);
root->AddComponent(meshRenderer);
//GameLoop
while(!quit)
{
root->Render();
}
source to share
It looks like you want to pass your objects by reference, use
void AddComponent(Component& component);
to avoid slicing .
For proper use with std::vector<>
and polymorphic inheritance, you need smart pointers, e.g. std::unique_ptr<Component>
to retain ownership, or std::shared_ptr<Component>
to share (both raw pointers Component*
might work, but much more difficult to manage correctly).
void AddComponent(std::unique_ptr<Component> componentPtr); // Unique ownership
or
void AddComponent(std::shared_ptr<Component> componentPtr); // Shared ownership
and correspondingly
std::vector<std::unique_ptr<Component>> components;
or
std::vector<std::shared_ptr<Component>> components;
It depends on your actual use cases if these instances Component
need to be uniquely owned by their aggregating parent class GameObject
or not.
To use pointers std::shared<>
that might expire outside of their scope, you can use std::weak_ptr<>
.
As mentioned, it totally depends on your use cases and how you want these aggregated components to be accessible from outside the class GameObject
.
source to share
It would be better if you could use unique_ptr
:
void AddComponent(std::unique_ptr<Component> component) {
components.push_back(std::move(component));
}
std::vector<std::unique_ptr<Component>> components;
Thus, by calling AddComponent()
, you transfer ownership of the component to GameObject
.
source to share