Сущность–компонент–система ( ECS ) — это программный архитектурный шаблон, который в основном используется в разработке видеоигр для представления объектов игрового мира. ECS включает сущности, состоящие из компонентов данных, с системами , которые работают с компонентами.
ECS следует принципу композиции по наследованию , что означает, что каждая сущность определяется не иерархией типов, а компонентами, которые с ней связаны. Системы действуют глобально по всем сущностям, которые имеют требуемые компоненты.
Особенно когда написано «Entity Component System», из-за неоднозначности в английском языке, общепринятая интерпретация названия заключается в том, что ECS — это система, включающая сущности и компоненты. Например, в докладе 2013 года на GDC [1] Скотт Билас сравнивает объектную систему C++ и свою новую пользовательскую компонентную систему. Это согласуется с традиционным использованием термина «система» в общей системной инженерии с Common Lisp Object System и системой типов в качестве примеров.
ECS объединяет ортогональные, устоявшиеся идеи в общей компьютерной науке и теории языков программирования . Например, компоненты можно рассматривать как идиому миксина в различных языках программирования. Компоненты являются специализированным случаем в рамках общего подхода делегирования и протокола метаобъектов . То есть, любая полная система объектов компонентов может быть выражена с помощью шаблонов и модели эмпатии в рамках видения объектно-ориентированного программирования Договора Орландо [2] .
Сущность : Сущность представляет собой объект общего назначения. Например, в контексте игрового движка каждый грубый игровой объект представлен как сущность. Обычно он состоит только из уникального идентификатора. Реализации обычно используют для этого простое целое число. [3]
Компонент : Компонент характеризует сущность как обладающую определенным аспектом и содержит данные, необходимые для моделирования этого аспекта. Например, каждый игровой объект, который может получить урон, может иметь компонент Health, связанный с его сущностью. Реализации обычно используют структуры , классы или ассоциативные массивы . [3]
Система : Система — это процесс, который действует на все сущности с желаемыми компонентами. Например, физическая система может запрашивать сущности, имеющие компоненты массы, скорости и положения, и перебирать результаты, выполняя физические вычисления на наборе компонентов для каждой сущности.
Поведение сущности может быть изменено во время выполнения системами, которые добавляют, удаляют или изменяют компоненты. Это устраняет проблемы неоднозначности глубоких и широких иерархий наследования, часто встречающиеся в методах объектно-ориентированного программирования , которые трудно понять, поддерживать и расширять. Общие подходы ECS в высокой степени совместимы с методами проектирования, ориентированными на данные, и часто сочетаются с ними . Данные для всех экземпляров компонента непрерывно хранятся вместе в физической памяти, что обеспечивает эффективный доступ к памяти для систем, которые работают со многими сущностями.
В 1998 году Thief: The Dark Project впервые использовал ECS. [4] Этот движок позже использовался в его продолжении, а также в System Shock 2 .
В 2002 году Скотт Билас из Gas Powered Games (Dungeon Siege) выступил с основополагающим докладом по ECS. [1] Это вдохновило на многочисленные более поздние известные реализации.
В начале января 2007 года Мик Уэст , работавший над серией игр Tony Hawk, поделился своим опытом внедрения ECS в Neversoft. [5]
Также в 2007 году команда, работающая над Operation Flashpoint: Dragon Rising , экспериментировала с проектами ECS, включая проекты, вдохновлённые Bilas/ Dungeon Siege , а Адам Мартин позже написал подробный отчёт о проектировании ECS, [6] включая определения основных терминов и концепций. [7] В частности, работа Мартина популяризировала идеи систем как первоклассных элементов, сущностей как идентификаторов, компонентов как необработанных данных и кода, хранящегося в системах, а не в компонентах или сущностях.
В 2015 году Apple Inc. представила GameplayKit — API- фреймворк для разработки игр для iOS , macOS и tvOS , включающий реализацию ECS. [8]
В августе 2018 года Сандер Мертенс создал популярный фреймворк flecs ECS. [9]
В октябре 2018 года [10] компания Unity выпустила свою демонстрационную версию мегаполиса, которая использовала технологический стек, построенный на ECS. ECS от Unity работает на мощной оптимизированной архитектуре, известной как DOTS, которая «позволяет создателям масштабировать обработку высокопроизводительным образом».
Структура данных различных ECS может различаться, равно как и определение компонентов, их связь с сущностями и то, как системы получают доступ к компонентам сущностей.
Адам Мартин в своей серии блогов определяет, что он считает сущностью-компонентом-системой. [7]
Сущность состоит только из идентификатора для доступа к компонентам. Обычной практикой является использование уникального идентификатора для каждой сущности. Это не является обязательным требованием, но имеет несколько преимуществ:
Некоторые из этих преимуществ также могут быть достигнуты с помощью интеллектуальных указателей .
Компоненты не имеют внутри себя игрового кода (поведения). Компоненты не обязательно должны быть физически расположены вместе с сущностью, но должны быть легкодоступны и доступны с помощью сущности.
«Каждая Система работает непрерывно (как будто у каждой Системы есть свой собственный частный поток) и выполняет глобальные действия над каждой Сущностью, которая обладает Компонентом или Компонентами, соответствующими запросу этой Системы».
Макет Unity содержит таблицы, каждая из которых содержит столбцы компонентов. В этой системе тип сущности основан на компонентах, которые он содержит. Для каждого типа сущности существует таблица (называемая архетипом ), содержащая столбцы компонентов, которые соответствуют компонентам, используемым в сущности. Чтобы получить доступ к определенной сущности, необходимо найти правильный архетип (таблицу) и индекс в каждом столбце, чтобы получить каждый соответствующий компонент для этой сущности.
Apparatus — это сторонняя реализация ECS для Unreal Engine , которая ввела некоторые дополнительные функции в общую парадигму ECS. Одной из этих функций является поддержка иерархии типов для компонентов. Каждый компонент может иметь базовый тип компонента (или базовый класс), как в ООП . Затем система может выполнить запрос с базовым классом и получить всех его потомков, сопоставленных в результирующем выборе сущностей. Это может быть очень полезно для некоторой общей логики, которая должна быть реализована на наборе различных компонентов, и добавляет дополнительное измерение в парадигму.
Flecs — это быстрая и легкая реализация ECS для C и C++, которая позволяет создавать игры и симуляции с миллионами сущностей.
Обычный способ передачи данных между системами — хранить данные в компонентах, а затем каждая система последовательно получает доступ к компоненту. Например, положение объекта может регулярно обновляться. Затем это положение используется другими системами. Если есть много разных редких событий, потребуется много флагов в одном или нескольких компонентах. Тогда системам придется отслеживать эти флаги на каждой итерации, что может стать неэффективным. Решением может быть использование шаблона наблюдателя . Все системы, зависящие от события, подписываются на него. Таким образом, действие из события будет выполнено только один раз, когда оно произойдет, и опрос не потребуется.
ECS не имеет проблем с проблемами зависимостей, которые обычно встречаются в объектно-ориентированном программировании, поскольку компоненты являются простыми контейнерами данных, у них нет зависимостей. Каждая система обычно запрашивает набор компонентов, которые должна иметь сущность, чтобы система могла с ней работать. Например, система рендеринга может регистрировать модель, преобразование и компоненты для рисования. Когда она работает, система будет выполнять свою логику для любой сущности, которая имеет все эти компоненты. Другие сущности просто пропускаются, без необходимости в сложных деревьях зависимостей. Однако это может быть местом, где могут скрываться ошибки, поскольку распространение значений из одной системы в другую через компоненты может быть сложным для отладки. ECS может использоваться там, где несвязанные данные должны быть привязаны к заданному времени жизни.
ECS использует композицию, а не деревья наследования. Сущность обычно состоит из идентификатора и списка компонентов, которые к ней прикреплены. Любой игровой объект может быть создан путем добавления правильных компонентов к сущности. Это позволяет разработчику легко добавлять функции к сущности без каких-либо проблем с зависимостями. Например, к сущности игрока может быть добавлен компонент пули , и тогда она будет соответствовать требованиям для манипулирования некоторой системой bulletHandler , что может привести к тому, что игрок будет наносить урон вещам, врезаясь в них.
Преимущества использования ECS для хранения игрового состояния были провозглашены многими разработчиками игр, такими как Адам Мартин. Хорошим примером являются записи в блоге Ричарда Лорда, где он обсуждает преимущества и то, почему разработанные ECS системы хранения игровых данных настолько полезны. [11]
Хотя ECS в основном используется в разработке видеоигр, он может быть полезен и в других областях. [12] [ нужен пример ]