如何从ECS中的模板方法获取组件?
How to get component from template method in ECS?
我正在开发一个实体组件系统游戏引擎,但在从实体中检索组件时遇到了麻烦。
这是我对实体的实现:
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 是包含在组件 class 中的枚举 class。实体指向的组件是静态类型的Component,动态类型是CRender、CInput等。也就是说,我有一堆组件作为组件 class 的子组件。
此外,我在不同的 class 中为每个组件保留了一些 smart_pointers。
代码的思路是检查map中的每一个组件,检查智能指针指向的指针类型
GetComponent() 方法是我正在努力工作的方法。
这里的 objective 是为了能够通过执行以下操作来检索任何组件(渲染组件的 CRender 等):
std::shared_ptr renderComponent = entity.GetComponent<CRender>();
很难弄清楚如何去做,因为我将组件存储在地图中,因此每种类型只能有 1 个组件。
我做错了什么?我也欢迎您提出任何更好的实施设计想法。提前致谢!
This seems to be the problem here:
if (typeid(component.second.get()) == typeid(T*))
The main issue is that typeid
when used with pointers will not get you the derived type like you are expecting. It’s going to give you the typeid
of “pointer-to-Component”, so you will always be evaluating typeid(pointer-to-Component) == typeid(pointer-to-DerivedComponent)
.
As for improvements, in your code you are not utilizing the lookup by key functionality of std::map
. Instead of looping through the map, you could change your GetComponent function to a non template function that takes the enum value as a parameter and use that to perform the map lookup.
Since you originally wrote a template function, as an alternative, you might benefit from changing the key type of your map to std::type_index
. This would allow you to do:
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)]);
}
And you should include logic to handle the case where the component is not found, like you do in your original code.
我正在开发一个实体组件系统游戏引擎,但在从实体中检索组件时遇到了麻烦。
这是我对实体的实现:
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 是包含在组件 class 中的枚举 class。实体指向的组件是静态类型的Component,动态类型是CRender、CInput等。也就是说,我有一堆组件作为组件 class 的子组件。 此外,我在不同的 class 中为每个组件保留了一些 smart_pointers。 代码的思路是检查map中的每一个组件,检查智能指针指向的指针类型
GetComponent() 方法是我正在努力工作的方法。 这里的 objective 是为了能够通过执行以下操作来检索任何组件(渲染组件的 CRender 等):
std::shared_ptr renderComponent = entity.GetComponent<CRender>();
很难弄清楚如何去做,因为我将组件存储在地图中,因此每种类型只能有 1 个组件。
我做错了什么?我也欢迎您提出任何更好的实施设计想法。提前致谢!
This seems to be the problem here:
if (typeid(component.second.get()) == typeid(T*))
The main issue is that typeid
when used with pointers will not get you the derived type like you are expecting. It’s going to give you the typeid
of “pointer-to-Component”, so you will always be evaluating typeid(pointer-to-Component) == typeid(pointer-to-DerivedComponent)
.
As for improvements, in your code you are not utilizing the lookup by key functionality of std::map
. Instead of looping through the map, you could change your GetComponent function to a non template function that takes the enum value as a parameter and use that to perform the map lookup.
Since you originally wrote a template function, as an alternative, you might benefit from changing the key type of your map to std::type_index
. This would allow you to do:
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)]);
}
And you should include logic to handle the case where the component is not found, like you do in your original code.