Проблема обработки пулов компонентов - Entity Subsystem

8

Описание архитектуры

Я создаю (проектирую) систему сущностей и столкнулся со многими проблемами. Я стараюсь максимально эффективно ориентировать их на данные и эффективность. Мои компоненты - это структуры POD (точнее, массив байтов), размещенные в однородных пулах. У каждого пула есть ComponentDescriptor - он просто содержит имя компонента, типы полей и имена полей.

Entity - это просто указатель на массив компонентов (где адрес действует как идентификатор объекта). EntityPrototype содержит имя сущности и массив имен компонентов. Наконец, подсистема (система или процессор), которая работает с пулами компонентов.

Актуальная проблема

Проблема заключается в том, что некоторые компоненты зависят от других (Model, Sprite, PhysicalBody, Animation зависит от компонента Transform), что создает много проблем при их обработке.

For example, lets define some entities using [S]prite, [P]hysicalBody and [H]ealth:
Tank:   Transform, Sprite, PhysicalBody
BgTree: Transform, Sprite
House:  Transform, Sprite, Health

and create 4 Tanks, 5 BgTrees and 2 Houses and my pools will look like:

TTTTTTTTTTT // Transform pool
SSSSSSSSSSS // Sprite pool
PPPP        // PhysicalBody pool
HH          // Health component

Нет способа обработать их, используя индексы. Я провожу 3 дня, работая над этим, и у меня все еще нет никаких идей. В предыдущих проектах TransformComponent был привязан к сущности, но это не было хорошей идеей. Можете ли вы дать мне несколько советов, как их обрабатывать? Или, может быть, я должен изменить общий дизайн? Возможно, мне следует создать пулы энтитов (пулы компонентных пулов) - но я думаю, что это будет кошмар для кешей процессоров.

Спасибо

mani3xis
источник
Мультиплеер? (Это актуально)
Джонатан Дикинсон

Ответы:

2

Отказ от ответственности: Чисто уходя от моих знаний класса систем.

Я изначально думал, почему бы просто не использовать хеш-функцию для идентификатора объекта для вашего индекса?

Таким образом, вы получите

T[A]nk:   Transform, Sprite, PhysicalBody
B[G]Tree: Transform, Sprite
H[O]use:  Transform, Sprite, Health

and create 4 Tanks, 5 BgTrees and 2 Houses and my pools will look like:

OGAGAGGOGGG // Entity pool (letters corresopnding to entity type)
TTTTTTTTTTT // Transform pool
SSSSSSSSSSS // Sprite pool
P P P  P    // PhysicalBody pool
H      H    // Health component

Или как бы то ни было, сущности оказались размещенными. Вы можете иметь пулы для всех компонентов и для сущностей и использовать пул сущностей в качестве «главного», так что коллизии проверяются по массиву сущностей. Но, конечно, вы сталкиваетесь с проблемой утилизации компонентов и объектов.

Если ваш игровой дизайн это позволяет, вы можете заранее планировать, куда идет каждый тип сущности, чтобы получить максимально эффективную упаковку. Скажем, сущности 0-20 зарезервированы для резервуаров, сущности 21-30 для домов и 31-60 для деревьев BG. Возможно, вы не сможете эффективно порождать бесконечные недобрые слова, и это своего рода побеждает динамизм компонентных систем, но это решит проблему. Я не вижу способа съесть твой торт и съесть его тоже.

Я думал о том, как, возможно, ускорить процесс рендеринга, когда у вас есть файл RenderingComponent, содержащий все данные, которые нужны системе рендеринга, чтобы она могла просто проходить через массив этих вещей, но тогда есть издержки на копирование данных. Кроме того, каждый раз, когда вы разыменовываете указатель, вы думаете о том, находится ли он в кэше или нет.

Если вы хотите очень быструю игру, я бы сказал, распланируйте ваше распределение. Если вам нужна гибкая игровая архитектура, разверните хеш-таблицы и строковые идентификаторы. В любое время, когда вам нужна гибкость, вам нужно создать абстракцию, и, следовательно, это потребует дополнительных затрат.

TL; DR;
Основываясь на том, что вы описали, я бы создал более высокий уровень RenderComponentс указателями Spriteи Transformкомпонентами и дал бы ему необходимые ссылки при инициализации объекта.

(Прошу прощения за любой предполагаемый бред, я тоже думал об этом в своей системе, так что это была возможность продумать это)

michael.bartnett
источник
Я не знаю, настолько ли эффективны хеш-карты. Я хочу иметь системы сущностей, в которых подсистемы содержат функции DOD, такие как: void update(u32 n, PhysicalBodyComponents* bodys, Transform* transforms)Я хочу работать со многими входами и разделить эту функцию на несколько ядер. Можно с хешмапами?
Mani3xis
Хеш-карты - это просто способ идентифицировать отношения между сущностями и компонентами. Это зависит от того, как настроена ваша игра, но я не вижу эффективного способа гарантировать, что ваш bodysи transformsмассив выстроятся в линию. Это просто то, что вы не можете обойти без добавления слоя абстракции или планирования своего размещения. Я чувствую, что у меня нет опыта, чтобы говорить о масштабировании до нескольких ядер. Может быть, найти вопрос о потоке и масштабировании или написать свой.
michael.bartnett
Масштабирование легко, когда функции работают с линейными массивами - я могу установить диапазон для каждого ядра и просто запустить его. Вот почему я пытаюсь избежать хэш-карт. Я буду пытаться изменить эту систему сущностей. Я должен быть очень осторожен с промахами кэшей - у PS2 очень ограниченная оперативная память и т. Д. Кстати: нет ничего невозможного :)
mani3xis
Нет ничего невозможного, но не все возможно;). Вы можете стремиться к простоте и элегантности реализации, скорости выполнения и потреблению памяти: выберите два. Когда вы найдете свое решение, пожалуйста, опубликуйте его как ответ. Я уверен, что я не единственный, кто хотел бы его увидеть.
Майкл Бартнетт