Разделение компонента в Entity-Component-System требует слишком много рефакторинга - PullRequest
2 голосов
/ 02 июля 2019

У меня есть работающая библиотека игр C ++, которая использует Entity-Component-System (ECS).

Пользователь моей библиотеки хотел бы создать некоторые компоненты, например Cat: -

class Cat{ public:
    int hp;
    float flyPower;
};

Он может изменить hp каждого cat, например: -

for(SmartComponentPtr<Cat> cat : getAll<Cat>()){
    cat->hp-=5;  //#1
}

Через несколько дней он хочет разделить Cat на HP и Flyable: -

class HP{ public:
    int hp;
};
class Flyable{ public:
    float flyPower;
};

Таким образом, каждый cat, имеющий доступ hp, будет компилировать ошибку (например, на #1 в приведенном выше коде.)

Чтобы решить, пользователь может изменить свой код на: -

for(MyTuple<HP,Flyable> catTuple : getAllTuple<HP,Flyable>()){
    SmartComponentPtr<HP> hpPtr=catTuple ; //<-- some magic casting
    hpPtr->hp-=5; 
}

Это работает, но требует много рефакторинга в коде пользователя (различные места, которые вызывают cat->hp).

Как отредактировать каркас / механизм для решения проблемы удобства сопровождения при разбиении компонента в ECS?

Я никогда не находил подходов, которые не страдают от этогонапример: -

1 Ответ

3 голосов
/ 02 июля 2019

Указатели членов на помощь:

#include <tuple>

template <typename... Components>
struct MultiComponentPtr {
    explicit MultiComponentPtr(Components*... components)
        : components_{components...}
    {}

    template <typename Component, typename Type>
    Type& operator->*(Type Component::* member_ptr) const {
        return std::get<Component*>(components_)->*member_ptr;
    }

private:
    std::tuple<Components*...> components_;
};

struct Cat {
    int hp;
    float flyPower;
};

struct HP {
    int hp;    
};

struct Flyable {
    float flyPower;    
};

int main() {
    {
        Cat cat;
        MultiComponentPtr<Cat> ptr(&cat);
        ptr->*&Cat::hp += 1;
        ptr->*&Cat::flyPower += 1;
    }

    {
        HP hp;
        Flyable flyable;
        MultiComponentPtr<HP, Flyable> ptr(&hp, &flyable);
        ptr->*&HP::hp += 1;
        ptr->*&Flyable::flyPower += 1;
    }
}

Технически вам все еще нужно выполнить рефакторинг, но тривиально автоматически заменить &Cat::hp на &HP::hp и т. Д.

...