Компонентная архитектура 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,

Другие вопросы по тегам