Я начал следовать учебному пособию по ECS на YouTube и никогда не видел, чтобы кто-то выделял новую переменную в vector
из uint8
до.
template<typename Component>
uint32 ECSComponentCreate(Array<uint8>& memory, EntityHandle entity, BaseECSComponent* comp)
{
uint32 index = memory.size();
memory.resize(index+Component::SIZE);
Component* component = new(&memory[index])Component(*(Component*)comp);
component->entity = entity;
return index;
}
(полный код можно найти Вот; Array
здесь #define Array std::vector
)
Чем он отличается от использования вектора указателей, почему он лучше?
Это в основном «распределитель пула». Теперь, когда вы знаете, как это называется, вы можете прочитать о том, почему это делается, но производительность, как правило, является мотивацией.
Все распределения выполняются в одном векторе, и в конце весь вектор может быть освобожден сразу (после уничтожения объектов внутри, что вы можете увидеть в функции освобождения чуть ниже).
Две ошибки мне с помощью vector
из байтов:
Если вы хотите, чтобы ваш ECS хранил новые типы компонентов непрерывно в памяти, то гораздо менее опасный подход, который я рекомендую, это абстрагировать контейнер компонентов, например:
struct Components
{
virtual ~Components() {}
};
template <class T>
struct ComponentsT: public Components
{
std::vector<T> components;
};
Когда вы хотите зарегистрировать новый тип компонента, Foo
для системы, вы можете динамически распределять и создавать ComponentsT<Foo>
вставьте это в полиморфный контейнер (контейнер контейнеров), и когда вы хотите добавить Foo
компонент к объекту (и, следовательно, создать его экземпляр и добавить его в список компонентов), получить соответствующий реферат Components*
Базовый указатель / ссылка, уменьшить его (можно использовать dynamic_cast
) чтобы ComponentsT<Foo>*
, затем отодвиньте туда свой компонентный экземпляр Теперь вы получили все свои Foos
хранится непрерывно в памяти, не имея дело с выравниванием и аннулированием и так далее.