我一直在调试另一个问题中的方法,即使它已得到固定的注释,但仍使我相信我做得不好,但没人能提出建议来改进它。
>我正在编写的渲染引擎使用受团结启发的组件系统。 GetComponent<>()
方法从对象中返回给定类型的组件(如果存在),如果给定组件不存在,则返回nullptr
。所有组件都从通用的Component
基类继承。
代码如下:
template <typename CompType>
inline CompType getComponent()
{
for(Component * currComp : compStruct.components)
{
CompType currentEntry = dynamic_cast<CompType>(currComp);
if (currentEntry != nullptr)
{
return currentEntry;
}
}
return nullptr;
}
用法如下:
//Returns a valid RenderConditions pointer if the object has that component
RenderConditions* rc = go->getComponent<RenderConditions*>();
dynamic_cast
显然是不可取的,尤其是因为此系统可以多次用于RenderComponents,AnimationComponents,Transform或其他任何帧。关于每种类型的组件都有一个固定的“ ID”,我有一些想法,但关键是我希望该游戏引擎的用户能够为系统编写自己的组件,而无需使用dynamic_cast我发现它只能与object.h中包含的组件一起使用。
任何想法如何改进?
答案 0 :(得分:1)
请勿使用此方法存储持久性(例如,在磁盘上)类型的元数据,因为typeid可能在同一程序的不同调用之间改变。
请注意:GetComponent
方法在Unity中确实很昂贵,因此不建议您频繁调用它(即每帧多次)。相反,您应该获取它并将结果缓存在其他位置。
因此,要实现此目的,您可以使用标准提供的typeid
运算符和std::type_index
。 std::type_index
对于每种类型都是唯一的,并且可以用作映射键(请参见this reference page)。
这是一个示例实现:
#include <typeindex>
#include <map>
#include <cassert>
//Base class of all components
class Component {
public:
virtual ~Component() = default;
Component(const Component& rhs) = delete;
protected:
Component() = default;
};
class Rigidbody : public Component {
};
class MeshRenderer : public Component {
};
class Text : public Component {
public:
std::string text;
};
class GameObject {
private:
std::multimap<std::type_index, Component*> m_components;
public:
template<typename T,
typename = std::enable_if_t<std::is_base_of_v<Component, T>>>
T* add_component() {
return dynamic_cast<T*>(m_components.insert(std::make_pair(std::type_index(typeid(T)), new T))->second);
}
template<typename T,
typename = std::enable_if_t<std::is_base_of_v<Component, T>>>
T* get_component() {
auto it = m_components.find(std::type_index(typeid(T)));
if (it == m_components.end()) return nullptr;
return dynamic_cast<T*>(it->second);
}
};
int main() {
GameObject gm;
gm.add_component<MeshRenderer>();
auto& text = *gm.add_component<Text>();
assert(gm.get_component<MeshRenderer>() != nullptr);
assert(gm.get_component<Rigidbody>() == nullptr);
text.text = "Hello, World!";
std::cout << gm.get_component<Text>()->text << std::endl;
return 0;
}
输出应为:Hello, World!