Я разрабатываю то, что будет игровым движком 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 компонент каждого типа.
Что я делаю неправильно? Также я бы приветствовал любые лучшие идеи дизайна реализации, которые у вас могут быть. Заранее спасибо!
Это, кажется, проблема здесь:
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)]);
}
И вы должны включить логику для обработки случая, когда компонент не найден, как вы делаете в своем исходном коде.
Других решений пока нет …