Я работаю над реализацией игрового движка, используя принципы ECS в качестве упражнения.В моем текущем проекте есть класс ComponentManager, в котором хранятся все векторы, соответствующие каждому типу компонента.Минимальная версия класса выглядит следующим образом:
class ComponentManager{
private:
std::vector<void*> componentHolder;
public:
bool destroyEntity(int entityID, componentSignature toDestroy);
template <class T>
int registerComponent();
template <class T>
bool addComponent(int entity, T initialComp);
template <class T>
bool removeComponent(int entity);
};
componentHolder - это вектор void *, где каждая запись - это вектор, содержащий другой тип компонента.Причина, по которой я это делаю, заключается в том, что я хочу хранить все компоненты в непрерывной памяти, однако каждый компонент имеет свой тип.Если бы я использовал вектор указателей на некоторый базовый класс компонентов, это нарушило бы согласованность кэша, ориентированные на поток данных преимущества, которые я пытаюсь использовать с этим механизмом ECS.
Кроме того, Мой движок спроектирован так, что другие могут создавать пользовательские компоненты, просто определяя структуру, содержащую данные, которые они хотят, чтобы этот компонент сохранял, и регистрируя этот компонент при создании нового игрового «мира» (или экземпляра).Если вы предпочитаете).Эта регистрация выполняется с помощью функции registerComponent (), показанной выше, которая создает уникальный идентификатор для каждого типа компонента и определяется как:
template <class T>
int ComponentManager::registerComponent(){
componentHolder.push_back(new std::vector<T>);
return type_id<T>();
}
Функция type_id () - это трюк, который я нашел из Этот вопрос об обмене стеками и позволяет мне сопоставлять типы компонентов с целыми числами, которые я использую в качестве индексов в векторе ComponentManager.Это хорошо сработало для создания / доступа к компонентам, поскольку эти функции являются шаблонами и получают тип переданного компонента (и в результате я могу статически приводить void *, который находится по индексу вектора componentHolder справатипа), вот пример этого:
template <class T>
bool ComponentManager::addComponent(int entityID){
int compID = type_id<T>();
std::vector<T>* allComponents = (std::vector<T>*)componentHolder[compID];
if (compEntityID.find(entityID) == compEntityID.end()){
(*allComponents).push_back(T());
return true;
}
return false;
}
однако проблема возникает, когда я хочу полностью уничтожить сущность.Моя функция для уничтожения сущности просто требует идентификатора сущности и подписи компонента (набора битов, биты которого равны 1, соответствующие компонентам этой сущности), который хранится в объекте gameWorld и передается внутрь. Однако, так как destroyEntityФункция не получает типы, передаваемые в нее через шаблонные функции, и имеет только набор битов, чтобы узнать, какой тип компонента нужно уничтожить. Я не могу найти способ получить тип, чтобы я мог привести void * к нужному вектору.,Вот пример того, что я хочу, чтобы функция destroyEntity делала:
bool ComponentManager::destroyEntity(int entityID, componentSignature toDestroy){
for (int x = 0; x < MAX_COMPONENT; x++){
if (toDestroy[x]){
std::vector<??>* allComponents = (std::vector<??>*)componentHolder[x]; // Here is where the issue lies
(*allComponents).erase((*allComponents).begin() + entityIndex);
}
}
}
Есть ли способ при регистрации компонента, например, чтобы я мог сохранить указатель функции на метод стирания каждого вектора, из которого я мог бы позже вызватьфункция destroyEntity ()?Или каким-то образом сохранить карту из целочисленного ID компонента, который я создаю при регистрации, в сам тип и использовать его позже для приведения?Типы компонентов, которые есть в игре, будут известны во время выполнения, поэтому я чувствую, что это должно быть выполнимо как-то?Также в качестве предостережения есть некоторая дополнительная логика, которую я должен выяснить, какой сущности принадлежит какой компонент в каждом компонентном векторе в componentHolder, который я пропустил для краткости, чтобы это не вызывало никаких проблем.
СпасибоAdvanced для вашей помощи / любые советы, которые вы можете предоставить!Я ценю, что вы читаете этот длинный пост, и я открыт для предложений!