В настоящее время я внедряю систему компонентов сущностей и работаю над способом сохранения векторов компонентов, каждый вектор одного типа компонентов должен быть смежным, поэтому я использую vector<Component>*
, а не vector<Component*>
. Я новичок в C ++ и пришел из Java, поэтому я все еще борюсь с некоторыми концепциями, касающимися разметки памяти и полиморфизма.
Я полностью реализовал (казалось бы) рабочую версию этого. У меня есть вектор для каждого типа компонента (например, PositionComponent, GravityComponent и т. Д.), Потому что компоненты отличаются по размеру. Но так как количество типов не известно во время компиляции, мне нужен вектор указателей для указания на эти ComponentLists разных типов. Я использую reinterpret_casts с картой, которая отслеживает типы компонентов для достижения этой цели, но должен быть менее неопределенный способ сделать это. (Надеюсь!)
Вот картина того, чего я хочу достичь:
Компоновка списка компонентов
Редактировать: я просто замечаю, что моя программа падает с ошибкой сегментации после return 0
в основной функции. Стек вызовов кажется поврежденным, так как он переходит на какой-то случайный адрес, а не возвращается. Так что моя система определенно несовершенна.
Основная функция:
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;
}
Класс EntityComponentSystem:
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;
}
};
Класс ComponentList:
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();
}
}
};
Класс базовых компонентов и его производные:
class Component
{
public:
typedef uint16_t TypeID;
static const TypeID TYPE_ID_UNKNOWN = -1;
virtual ~Component() = default;
virtual void test()
{
std::cout << "I'm the base!" << std::endl;
}
};
class AComponent : public Component
{
private:
static int nextValue;
int someValue; // To test if different sizes of Component derivatives cause any problems!
public:
AComponent()
{
this->someValue = nextValue++;
}
void test()
{
std::cout << "I'm AComponent! Value: " << someValue << std::endl;
}
};
int AComponent::nextValue = 0;
class BComponent : public Component
{
public:
void test()
{
std::cout << "I'm BComponent!" << std::endl;
}
};
class CComponent : public Component
{
public:
void test()
{
std::cout << "I'm CComponent!" << std::endl;
}
};