Общие и зависимые компоненты ECS / CES и локальность кэша
Я пытался обдумать, как работает ECS, когда есть общие или зависимые компоненты. Я прочитал множество статей о ECS и не могу найти однозначного ответа на этот вопрос.
Предположим следующий сценарий:
У меня есть объект, который имеет ModelComponent (или MeshComponent), PositionComponent и ParticlesComponent (или EmitterComponent).
Для ModelRenderSystem требуется как ModelComponent, так и PositionComponent.
ParticleRenderSystem требуется ParticlesComponent и PositionComponent.
В ModelRenderSystem, для эффективности / локальности кэша, я хотел бы прогнать все ModelComponents, которые находятся в компактном массиве, и отобразить их, однако для каждой модели мне нужно получить PositionComponent. Я даже не задумывался о том, как работать с текстурами, шейдерами и т. Д. Для каждой модели (что определенно разрушит кэш).
Аналогичная проблема с ParticleRenderSystem. Мне нужен как ParticlesComponent, так и PositionComponent, и я хочу, чтобы все компоненты ParticlesComponent могли проходить эффективно и дружественно.
Я подумал о том, чтобы ModelComponent и ParticlesComponent имели свои собственные позиции, но их нужно будет синхронизировать каждый раз, когда положение модели изменяется (представьте, как частица воздействует на персонажа). Это добавляет другую сущность или компонент, который должен отслеживать и синхронизировать компоненты или значения (и потенциально сводит на нет любую эффективность кэширования).
Как все остальные справляются с такими проблемами зависимости?
1 ответ
Одним из способов уменьшить сложность может быть инвертирование потока данных.
Считайте, что ваш ModelRenderSystem
имеет обратный вызов слушателя, который позволяет платформе сущности информировать ее о том, что сущность была добавлена в симуляцию, которая содержит и позицию, и компонент модели. Во время этого обратного вызова система может зарегистрировать обратный вызов для компонента позиции или системы, которой принадлежит этот компонент, что позволяет ModelRenderSystem
быть информированным, когда объект этой позиции изменяется.
По мере того, как происходят изменения от изменений позиции, ModelRenderSystem
может поставить в очередь список модификаций, которые он должен реплицировать во время фазы обновления, а затем во время обновления, это действительно простой поиск каждой модели модификаций и установка позиции на значение в событии.
Преимущество состоит в том, что для каждого кадра вы реплицируете только те изменения положения, которые фактически изменились во время кадра, и вы минимизируете поиск, необходимый для репликации данных. В то время как обновление позиции распространяется на различные системы, представляющие интерес, может быть не столь благоприятно для кэша, выгоды, которые вы наблюдаете в противном случае, весят это.
Наконец, не забывайте, что системы не обязательно должны перебирать нужные компоненты. Компоненты в вашей системе сущностей существуют, чтобы вы могли легко переключать поведение подключаемых модулей. Системы всегда могут управлять более удобной для кэша структурой данных и, используя описанный выше подход обратного вызова, позволяют вам сделать это и управлять репликацией данных очень легко с минимальной связью.