Как получить компонент из шаблонного метода в ECS? - PullRequest
0 голосов
/ 13 октября 2018

Я занимаюсь разработкой игрового движка Entity Component System, и у меня возникают проблемы с извлечением компонента из сущности.

Вот моя реализация сущности:

class Entity {
public:
    Entity(int l_id);

// ...

template <typename T>
std::shared_ptr<T> GetComponent() { // T = CRender, CInput, etc
    for (auto& component : m_components) {
        if (typeid(component.second.get()) == typeid(T*)) {
            return std::dynamic_pointer_cast<T>(component.second);
        }
    }
    return nullptr;
}

private:
    int m_id;
    std::string m_name;
    std::unordered_map<ComponentType, std::shared_ptr<Component>> m_components;

ComponentType - это класс перечисления, содержащийся в классе Component.Компоненты, на которые указывают сущности, это Component в статическом типе, а CRender, CInput и т. Д. В динамическом типе.То есть у меня есть несколько компонентов как дочерние компоненты класса Component.Кроме того, я держу несколько smart_pointers для каждого компонента в разных классах.Идея кода состоит в том, чтобы проверить каждый компонент на карте и проверить тип указателя, на который указывает умный указатель

Этот метод GetComponent () - это то, что я пытаюсь заставить работать.Цель в том, чтобы иметь возможность получить любой компонент (CRender для компонента рендеринга и т. Д.), Выполнив что-то вроде этого:

std::shared_ptr renderComponent = entity.GetComponent<CRender>();

Трудно понять, как это сделать, поскольку яхранение компонентов на карте, так что может быть только 1 компонент каждого типа.

Что я делаю не так?Также я бы приветствовал любые лучшие идеи дизайна реализации, которые у вас могут быть.Заранее спасибо!

1 Ответ

0 голосов
/ 14 октября 2018

Здесь, похоже, проблема:

if (typeid(component.second.get()) == typeid(T*)) 

Основная проблема в том, что typeid при использовании с указателями не даст вам производный тип, как вы ожидаете.Он даст вам typeid «указателя на компонент», так что вы всегда будете оценивать typeid(pointer-to-Component) == typeid(pointer-to-DerivedComponent).

Что касается улучшений, в вашем коде вы не используете поиск по ключевым функциямstd::map.Вместо того, чтобы проходить по карте, вы можете изменить функцию GetComponent на не шаблонную функцию, которая принимает значение перечисления в качестве параметра и использует его для поиска карты.

Поскольку вы изначально написали функцию шаблона, какВ качестве альтернативы вы могли бы выиграть от изменения типа ключа вашей карты на std::type_index.Это позволит вам сделать:

std::map<std::type_index, std::shared_ptr<Component>> components;

template <typename T>
std::shared_ptr<T> GetComponent() {
    return std::dynamic_pointer_cast<T>(components[typeid(T)]);
}

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

...