我正在重新构建实体组件系统的实体管理器。由于组件没有重叠的功能,我不希望它们有一个我可以存储的共享基础。
所以我想出了类似的东西:
#include <vector>
#include <memory>
#include <iostream>
class Component1{};
class Component2{};
class Component3{};
class Manager{
public:
template<typename T> static std::vector<std::shared_ptr<T>> component;
template<typename T> static std::shared_ptr<T> getComponent(int nth){
return component<T>[nth];
}
template<typename T> static std::shared_ptr<T> addComponent(int nth){
return component<T>[nth] = shared_ptr<T>(new T());
}
static void addEntity(){
// push back a nullptr for every instantiated component<>
}
static void removeEntity(int nth){
// set the nth index of every component<> to nullptr
}
};
template<typename T>
std::vector<std::shared_ptr<T>> Manager::component = std::vector<std::shared_ptr<T>>();
int main(){
Manager::component<Component1>;
Manager::component<Component2>;
Manager::component<Component3>;
Manager::addEntity();
auto cmp2 = Manager::getComponent<Component2>(0);
Manager::removeEntity(0);
std::cin.get();
return 0;
}
如何迭代这两个函数的实例化组件?尝试使用type_info的向量来存储Component类型,但我永远无法从中获取正确的类型以用作模板参数。
答案 0 :(得分:2)
您可以首先使用模板元编程技巧get a unique ID for your types。 然后,您可以使用带有唯一类型ID 的地图,而不是您的变量模板向量。通过将多态性与基础Component类相结合,再加上static_cast(以减少运行时成本),您可以轻松地重新实现以前的 addComponent 和 getComponent 方法。由于地图访问权限,它们的成本会稍微高一些,但最终您可以通过迭代地图来实现 addEntity 和 removeEntity ,完全按照您的要求执行想要的。
以下是我对上述想法的实施:
#include <vector>
#include <map>
#include <memory>
#include <iostream>
typedef void(*unique_id_type)();
template <typename... Arguments>
struct IdGen {
static constexpr inline unique_id_type get_unique_id()
{
return &IdGen::dummy;
}
private:
static void dummy() {};
};
class Component {};
class Component1 : public Component {};
class Component2 : public Component {};
class Component3 : public Component {};
class Manager {
public:
static std::map<unique_id_type, std::vector<std::shared_ptr<Component>>> components;
template<typename T> static std::shared_ptr<T> getComponent(int nth) {
return std::static_pointer_cast<T>(components[IdGen<T>::get_unique_id()][nth]);
}
template<typename T> static std::shared_ptr<T> addComponent(int nth) {
return std::static_pointer_cast<T>(components[IdGen<T>::get_unique_id()][nth] = std::shared_ptr<T>(new T()));
}
static void addEntity() {
for (auto& component : components)
component.second.push_back(nullptr);
}
static void removeEntity(int nth) {
for (auto& component : components)
component.second[nth] = nullptr;
}
};
std::map<unique_id_type, std::vector<std::shared_ptr<Component>>> Manager::components = {
{ IdGen<Component1>::get_unique_id(), {} },
{ IdGen<Component2>::get_unique_id(), {} },
{ IdGen<Component3>::get_unique_id(), {} },
};
int main() {
Manager::addEntity();
auto cmp2 = Manager::getComponent<Component2>(0);
Manager::removeEntity(0);
std::cin.get();
return 0;
}
PS =这段代码使用了c ++ 11的功能,例如constexpr和列表初始化,但由于你已经在使用C ++ 14(即使你没有将你的问题标记为C ++ 14),我认为这是不是问题。
PS 2 =由于我使用static_cast进行向下转换,因此不应对组件使用虚拟继承(阅读why)。