Обработка компонентов ECS - PullRequest
0 голосов
/ 25 октября 2018

В моем игровом движке ECS создаются состояния, которые регистрируют определенное количество объектов и присваивают им их компоненты.Функции обновления систем вызываются один раз за цикл обновления.На этом этапе они запрашивают текущее игровое состояние (через статическую ссылку на менеджер состояний) для соответствующих типов компонентов (то есть: система рендеринга запрашивает компоненты рендеринга и позиционирования).

Состояния игры нуждаются в способе хранения своих сущностей и соответствующих компонентов, а также в предоставлении системам контейнера компонентов определенного типа.Как я могу хранить компоненты, производные от базового класса компонентов, чтобы системы могли получать производные классы?

Некоторые из решений, которые я читал в Интернете, включают:

  • Использованиекарта сущностей и общие указатели на их компоненты, которые предположительно не будут разбивать производную часть, и я могу использовать dynamic_cast, чтобы вернуть их в их производное состояние
  • Используя то, что называется идиомой PIMPL, что я полностьюне понимаю

Должен ли я использовать одну карту?Два?Должны ли они содержать общие или слабые указатели, или нет?Как мне написать свою шаблонную функцию для возврата производных классов компонентов?

component.hpp

struct Component {

public:

    // Perhaps some sort of static derived class identifier would go here

};

typedef vector<Component> ComponentVector;

state.hpp

class State {

protected:

    // The game class is the game's entry point, where states and systems are created. 
    // It also holds a reference to the state and system managers, so they can be 
    // accessed by each other
    friend class Game;

    static Game *game;

    // ie: assignComponent<RenderComponent>(player)
    template <typename C, typename Args ...>
    void assignComponent(Entity entity, Args && ... args);

    Entity createEntity();

    void destroyEntity();

    template <typename C>
    ComponentVector<C> getComponents();

public:

    // The names identify each state so the state manager can queue them
    const StateName name;

    typedef shared_ptr<State> Pointer;

    State(StateName name) : name(name) {}

    virtual void registerEntities() = 0;

    virtual ~State() {}

};

overworld_state.hpp (пример производного класса состояний)

class OverworldState : public State {

public:

    OverworldState() : State(OVERWORLD) {}

    void registerEntities() {
        Entity player = createEntity();
        assignComponent<RenderComponent>(player);
    }

};

system.hpp

class System {

protected:

    friend class Game;

    static Game *game;

public:

    virtual void update() = 0;

    virtual ~System() {}

};

render_system.hpp (пример системного класса)

class RenderSystem : public System {

public:

    void update() {
        // Pseudo code of how I would like it to work:
        ComponentVector<RenderComponent> components =
                game.currentState.getComponents<RenderComponent>();
    }

};
...