如何从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.