如何从ECS中的模板方法获取组件?

How to get component from template method in ECS?

本文关键字:模板方法 获取 组件 ECS      更新时间:2023-10-16

我正在开发实体组件系统游戏引擎,在从实体检索组件时遇到麻烦。

这是我对实体的实现:

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;

组件类型是包含在组件类中的枚举类。实体指向的组件是静态类型的组件,但动态类型的 CRender、CInput 等。也就是说,我有一堆组件作为组件类的子级。 此外,我保留了不同类中每个组件的一些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)]);
}

并且您应该包含逻辑来处理找不到组件的情况,就像在原始代码中所做的那样。