【发布时间】:2017-09-01 16:32:26
【问题描述】:
您可能听说过Entity Component System,其中所有内容都是Entity,每个实体都有一个控制其功能的Components 列表。
我正在尝试找出如何将不同的对象(每个都继承 Component)存储在一个数组中,并能够根据它们的类型从该数组中取出一个对象。
我能想到的第一个解决方案是为继承组件的对象类型设置一个enum:
enum ComponentType : unsigned char // There will never be more than 256 components
{
EXAMPLE_COMPONENT,
ANOTHER_EXAMPLE_COMPONENT,
AND_ANOTHER_EXAMPLE_COMPONENT
};
然后Component 基类有一个带有getter 的ComponentType type;,每个子组件设置它的类型,例如:
ExampleComponent::ExampleComponent()
{
type = EXAMPLE_COMPONENT;
}
然后我会有一个GetComponent 函数:
Component* Entity::GetComponent(ComponentType type)
{
for (unsigned int i = 0; i < m_components.size(); i++)
{
if (m_components.at(i).GetType() == type)
{
return &m_components.at(i);
}
}
return nullptr;
}
// Note: m_components is an std::vector;
最后你会打电话给GetComponent 例如:
(ExampleComponent*) component = entity.GetComponent(EXAMPLE_COMPONENT);
这样做的问题是您需要为每种类型的组件提供一个enum,并且您还必须在使用GetComponent 之后强制转换组件以确保您可以访问它自己的成员变量。
有没有人知道在不需要enum 并且不需要强制转换组件的情况下执行此操作的正确方法?如果有一个解决方案仍然需要在每个组件中存储一个类型变量,它最好是一个字节,并且不能大于 4 个字节。
编辑:我也不想使用模板
提前致谢!
大卫
【问题讨论】:
-
我会将
Entity::GetComponent中的原始循环替换为std::find_if和一个lambda。我还将NULL的使用更改为nullptr并摆脱 C 风格的演员(ExampleComponent*)并用适当的 C++ 演员替换它。还;void*很讨厌 - 为什么不返回一个基类指针......? -
模板和
dynamic_cast? -
对我来说,您的
enum似乎模拟了多态性。通过创建派生类来使用真正的多态性。 -
顺便说一句:模板提供“编译时多态性”,派生类提供“运行时多态性”。你想要后者。
-
是的,它会起作用,因为您编译代码以支持“运行时类型信息”。例如。对于
g++,您不得使用-fno-rtti编译器选项。我不期望“最佳性能”,另请参阅stackoverflow.com/questions/4050901/performance-of-dynamic-cast。该问题的部分最佳答案是“我知道您不想谈论这个,但“大量使用 dynamic_cast 的设计”可能表明您做错了什么……”