我目前正在制作一个实体-组件-系统程序作为学习 C++ 的一种方式(我知道这可能不是推荐的方式,但我很开心)。到目前为止进展顺利,但我希望对其进行更多改进。
当前,每个系统都添加到 ECS 管理器中,std::function
并附有它需要运行的组件的签名。我当前的策略是遍历每个系统和实体,如果组件签名匹配,则使用实体 ID 作为参数调用系统函数。
// System function
static Game::runSystem(Manager & mngr, int id) {
ComponentA * a = mngr.getComponent<ComponentA>(id);
ComponentB * b = mngr.getComponent<ComponentB>(id);
// Do something with a and b
}
此函数通过以下方法附加到 Manager:
// Definition
template<typename...Args>
void Manager::addSystem(std::function<void(XManager & mngr, int id)> f); // A bitmask signature is generated based on the template
// Use
manager.addSystem<ComponentA, ComponentB>(Game::runSystem);
ComponentA
并且ComponentB
只是泛型类型。我什至可以让一个组件成为一个float
或者int
如果我需要的话。使用时getComponent<T>()
,这些被转换为适当的指针。
这一切都完美无缺,但最终发生的是我必须为每个系统包含管理器的头文件,我希望它们不要相互绑定(我想这将是关注点分离)。
最好每个过程最终看起来都类似于:
static Game::runSystem(ComponentA * a, ComponentB * b) {
// Do something with a and b
}
系统唯一需要知道的是它正在处理的特定实体的组件指针。
我目前std::unordered_map
根据其类型的位掩码将组件存储在一个中。当需要一个组件时,模板提供了我能够从中制作位掩码然后转换它的类型。我不确定是否可以存储要转换的组件的类型,所以我认为每个组件都必须作为 void 指针传递给函数。但是 C++ 不允许我在void*
不知道类型的情况下从 a 隐式转换为另一个指针。有没有办法可以存储每个组件的类型以便以后需要时进行转换?
我想我可能只void*
为系统所需的每个组件定义函数,但直观地说这似乎是个坏主意。它根本不是类型安全的,我无法通过查看函数声明来知道它需要什么参数。
如何将引用传递给可以采用任意数量的任何类型的指针的函数?有没有办法通过模板来做到这一点,或者我可以在不知道类型的情况下隐式转换一个 void 指针?我也对其他策略持开放态度。