我当前正在实现一个实体组件系统,并正在研究一种存储组件向量的方法,一个组件类型的每个向量都应该是连续的,这就是为什么我使用vector<Component>*
而不是{{1 }}。我是C ++的新手,来自Java,所以我仍在与有关内存布局和多态性的一些概念作斗争。
我已经完全实现了(看似)这个版本。我对每种类型的组件都有一个向量(例如PositionComponent,GravityComponent等),因为组件的大小不同。但是因为类型的数量在编译时未知,所以我需要一个指针向量来指向这些不同类型的ComponentList。我正在将reinterpret_casts与一个映射一起使用,该映射跟踪组件类型来完成此操作,但是必须有一种不太明确的方式来执行此操作。 (希望如此!)
这是我要实现的目标的图片: Component List Layout
编辑:我只是注意到我的程序在主功能中的vector<Component*>
之后由于段错误而崩溃。调用栈似乎已损坏,因为它跳转到某个随机地址而不是实际返回。所以我的系统肯定有缺陷。
主要功能:
return 0
EntityComponentSystem类:
int main(int argc, char** argv)
{
EntityComponentSystem ecs;
// Fill with some components
for(int i = 0; i < 5; ++i)
{
ecs.addComponent(AComponent());
ecs.addComponent(BComponent());
ecs.addComponent(CComponent());
}
// Print all components
std::cout << "Components: " << std::endl;
// Print AComponents
std::cout << "A Components: " << std::endl;
ComponentList<AComponent>* aComps = ecs.getComponentList<AComponent>();
aComps->print();
// Print BComponents
std::cout << std::endl << "B Components: " << std::endl;
ComponentList<BComponent>* bComps = ecs.getComponentList<BComponent>();
bComps->print();
// Print CComponents
std::cout << std::endl << "C Components: " << std::endl;
ComponentList<CComponent>* cComps = ecs.getComponentList<CComponent>();
cComps->print();
return 0;
}
ComponentList类:
class EntityComponentSystem
{
private:
// To shorten some things up
typedef std::vector<ComponentList<Component>*>::iterator ComponentListIterator;
typedef std::unordered_map<std::type_index, Component::TypeID>::iterator MapIterator;
std::vector<ComponentList<Component>*> comps; // Indexed by TypeID
std::unordered_map<std::type_index, Component::TypeID> componentMap; // Maps typeid(Component) to TypeID
public:
EntityComponentSystem() : comps(), componentMap() {}
~EntityComponentSystem()
{
for(ComponentListIterator it = comps.begin(); it < comps.end(); ++it)
{
delete (*it);
}
}
template<typename T>
void addComponent(const T& component)
{
static_assert(std::is_base_of<Component, T>::value, "T must be of type Component!");
MapIterator found = componentMap.find(typeid(T));
ComponentList<T>* componentList = nullptr;
if(found == componentMap.end()) // This component derivative hasn't been added yet, so add it
{
componentList = new ComponentList<T>();
int componentId = comps.size();
this->comps.push_back(reinterpret_cast<ComponentList<Component>*>(componentList));
this->componentMap[typeid(T)] = componentId;
}
else
{
componentList = reinterpret_cast<ComponentList<T>*>(comps[found->second]);
}
componentList->push(component);
}
template<typename T>
ComponentList<T>* getComponentList()
{
Component::TypeID id = getComponentTypeId<T>();
if(id == Component::TYPE_ID_UNKNOWN) return nullptr;
return reinterpret_cast<ComponentList<T>*>(comps[id]);
}
template<typename T>
Component::TypeID getComponentTypeId()
{
static_assert(std::is_base_of<Component, T>::value, "T must be of type Component!");
MapIterator found = componentMap.find(typeid(T));
if(found == componentMap.end())
{
return Component::TYPE_ID_UNKNOWN;
}
return found->second;
}
};
基本组件类及其派生类:
template<typename T>
class ComponentList
{
private:
std::vector<T> components;
public:
void push(const T& t)
{
this->components.push_back(t);
}
void print()
{
for(typename std::vector<T>::iterator it = components.begin(); it != components.end(); ++it)
{
it->test();
}
}
};