EnglishРусский Map

Entity Component System

title
Entity Component System
type
concept
summary
Data-oriented архитектура: сущности как ID, компоненты как данные, системы как пакетные итераторы
tags
architecture, game-dev, data-oriented-design
created
2026-04-10
updated
2026-04-10
lang
ru
source_updated
2026-04-10
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Entity Component System (ECS) - паттерн data-oriented архитектуры, в котором объекты разделяются на три части: сущности (идентичность), компоненты (данные) и системы (поведение). Он заменяет иерархии классов композицией: вместо class Player extends Character extends Entity получается сущность с прикреплёнными компонентами Position, Health, Sprite и PlayerInput, а также системы, которые итерируют по конкретным комбинациям компонентов.

Три составляющие:

Сущности (Entities) - это просто идентификаторы. Сущность представляет собой uint64 или дескриптор с учётом поколений (generation-indexed handle); у неё нет собственных данных или поведения. Это метка, к которой привязываются компоненты.

Компоненты (Components) - простые структуры данных: Position{X, Y float64}, Velocity{DX, DY float64}, Health{Current, Max int}. Никаких методов, никакого наследования, никакого полиморфизма. Компоненты прикрепляются к сущностям во время выполнения и могут динамически добавляться или удаляться, меняя то, чем сущность является, без изменения её типа в системе типов языка.

Системы (Systems) - функции, которые запрашивают сущности, подходящие под фильтр компонентов, и итерируют по ним. Физическая система запрашивает все сущности одновременно с Position и Velocity, считывает скорость и обновляет позицию. Система отрисовки запрашивает все сущности с Position и Sprite и отрисовывает их. Системы ничего не знают друг о друге и не хранят ссылок на конкретные сущности - они работают со множеством сущностей, соответствующих их фильтру.

Почему это работает

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

В ECS на базе архетипов (archetype-based) все сущности с одинаковым набором компонентов ("архетипом") хранятся в непрерывных массивах, по одному на каждый тип компонента. Итерация по всем компонентам Position превращается в линейный проход по плотному массиву. Для prefetcher'а кэша процессора это идеальный сценарий. Для систем, обрабатывающих тысячи сущностей за кадр (физика, коллизии, отрисовка), разница может достигать порядка.

Archetype-based против sparse-set

Две основные стратегии хранения:

Archetype-based (используется в Unity DOTS, Bevy, Ark): сущности группируются по комбинации компонентов. Добавление или удаление компонента перемещает сущность в таблицу другого архетипа. Итерация максимально эффективна для кэша; мутация компонентов (добавление/удаление) обходится дороже, так как требует перемещения между таблицами.

Sparse-set (используется в EnTT, flecs до версии v4): для каждого типа компонентов есть собственный sparse set, сопоставляющий ID сущностей с плотным хранилищем. Итерация в рамках одного компонента быстрая, но запросы по нескольким типам компонентов требуют пересечения множеств. Добавление и удаление обходятся дёшево - достаточно вставить элемент в набор или удалить из него.

Большинство современных ECS-фреймворков склоняются к archetype-based, поскольку нагрузка с преобладанием итераций (игровой цикл, такт симуляции) на практике значительно превышает операции добавления и удаления.

За пределами игр

ECS естественен для игровых движков, но паттерн применим везде, где есть большая коллекция разнородных сущностей, обрабатываемых пакетами. Симуляции (агентное моделирование, системы частиц), робототехника (потоки данных с сенсоров через конвейеры обработки) и процессы обработки данных - всё это отлично укладывается в ECS. Главный вопрос в том, какова специфика нагрузки: "итерировать по множеству сущностей, выполняя одну и ту же операцию" (здесь выигрывает ECS) или "выполнять сложные операции над отдельными объектами" (для этого вполне подходит ООП).

behavior-tree служит дополняющим паттерном: он отвечает за логику принятия решений для отдельных сущностей, тогда как ECS берёт на себя организацию данных в памяти и массовую обработку. И go-bt, и Ark - это библиотеки на Go, которые можно объединить в игре или симуляции.