Компонентная архитектура C++
У меня проблемы с поиском способа сделать архитектуру движка на основе компонентов в C++. Но я не могу придумать, как объединить вектор компонентов с классом, производным от компонента.
Я хочу переопределить компоненты виртуальной функции. Но единственный способ, которым я могу заставить ее вызывать переопределенную функцию - это сделать указатель на класс, производный от компонента, но я хочу, чтобы каждый игровой объект содержал свои собственные компоненты в векторе, а не вне класса в качестве указателя.
Я пытался удалить как можно больше ненужного кода.
Моя структура:
//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();
}
2 ответа
Похоже, вы хотите передать ваши объекты по ссылке, используйте
void AddComponent(Component& component);
чтобы избежать нарезки.
Для правильного использования с std::vector<>
и полиморфное наследование, вам понадобятся умные указатели, например std::unique_ptr<Component>
сохранить право собственности или std::shared_ptr<Component>
для совместной собственности (необработанные указатели как Component*
может также работать, но гораздо сложнее правильно управлять).
void AddComponent(std::unique_ptr<Component> componentPtr); // Unique ownership
или же
void AddComponent(std::shared_ptr<Component> componentPtr); // Shared ownership
и соответственно
std::vector<std::unique_ptr<Component>> components;
или же
std::vector<std::shared_ptr<Component>> components;
Это зависит от ваших реальных случаев использования, если эти Component
экземпляры должны однозначно принадлежать их объединяющему родителю GameObject
класс или нет.
Использовать std::shared<>
указатели, срок действия которых может истечь за пределами области их использования, которые вы можете использовать std::weak_ptr<>
,
Как уже упоминалось, это полностью зависит от ваших вариантов использования и от того, как вы хотите, чтобы эти агрегированные компоненты были доступны извне GameObject
учебный класс.
Было бы лучше, если бы вы могли использовать unique_ptr
:
void AddComponent(std::unique_ptr<Component> component) {
components.push_back(std::move(component));
}
std::vector<std::unique_ptr<Component>> components;
Таким образом, позвонив AddComponent()
Вы передаете право собственности на компонент, содержащий GameObject
,