Вступление
Сущностно-компонентные системы являются объектно-ориентированной архитектурной техникой.
Не существует единого мнения о том, что означает этот термин, так же как и объектно-ориентированное программирование. Тем не менее, очевидно, что системы объект-компонент специально предназначены в качестве архитектурной альтернативы наследованию . Наследование иерархия является естественной для выражения того, что объект является , но в некоторых видах программного обеспечения (например, игры), вы предпочли бы выразить то , что объект делает .
Это объектная модель, отличная от «классов и наследования», к которой вы, скорее всего, привыкли работать в C ++ или Java. Сущности так же выразительны, как классы, так же, как прототипы, как в JavaScript или Self - все эти системы могут быть реализованы в терминах друг друга.
Примеры
Давайте скажем , что Player
является юридическим лицом с Position
, Velocity
и KeyboardControlled
компонентов, которые делают очевидные вещи.
entity Player:
Position
Velocity
KeyboardControlled
Мы знаем , что Position
должны быть затронуты Velocity
, и Velocity
по KeyboardControlled
. Вопрос в том, как мы хотели бы смоделировать эти эффекты.
Сущности, компоненты и системы
Предположим, что компоненты не имеют ссылок друг на друга; внешняя Physics
система пересекает все Velocity
компоненты и обновляет Position
соответствующую сущность; Input
система проходит через все KeyboardControlled
компоненты и обновляет Velocity
.
Player
+--------------------+
| Position | \
| | Physics
/ | Velocity | /
Input | |
\ | KeyboardControlled |
+--------------------+
Это удовлетворяет критериям:
Эти системы в настоящее время отвечает за обработку событий и принятие поведения , описанные компонентами. Они также отвечают за обработку взаимодействий между объектами, таких как столкновения.
Сущности и компоненты
Однако предположим , что компоненты делают имеют ссылки друг к другу. Теперь сущность - это просто конструктор, который создает некоторые компоненты, связывает их вместе и управляет их временем жизни:
class Player:
construct():
this.p = Position()
this.v = Velocity(this.p)
this.c = KeyboardControlled(this.v)
Теперь объект может отправлять события ввода и обновлять данные напрямую своим компонентам. Velocity
будет отвечать на обновления и KeyboardControlled
будет реагировать на ввод. Это все еще удовлетворяет нашим критериям:
Сущность является «тупым» контейнером, который только перенаправляет события компонентам.
Каждый компонент определяет свое собственное поведение.
Здесь взаимодействие компонентов является явным, а не навязывается системой извне. Данные, описывающие поведение (какова величина скорости?) И код, который его определяет (какова скорость?), Связаны, но естественным образом. Данные можно рассматривать как параметры поведения. А некоторые компоненты не действуют вообще Position
- это поведение на месте .
Взаимодействия могут обрабатываться на уровне объекта («когда Player
столкновение с Enemy
…») или на уровне отдельных компонентов («когда объект с Life
сталкивается с объектом с Strength
…»).
Компоненты
Какова причина существования сущности? Если это просто конструктор, то мы можем заменить его функцией, возвращающей набор компонентов. Если позже мы захотим запрашивать сущности по их типу, мы также можем иметь Tag
компонент, который позволяет нам делать это:
function Player():
t = Tag("Player")
p = Position()
v = Velocity(p)
c = KeyboardControlled(v)
return {t, p, v, c}
Сущности настолько глупы, насколько это возможно - они просто наборы компонентов.
Компоненты отвечают непосредственно на события, как и раньше.
Взаимодействия должны теперь обрабатываются абстрактными запросами, полностью развязка событий из типов сущностей. Больше нет типов сущностей для запроса - произвольные Tag
данные, вероятно, лучше использовать для отладки, чем игровая логика.
Вывод
Объекты не являются функциями, правилами, субъектами или комбинаторами потоков данных. Это существительные, которые моделируют конкретные явления - иными словами, они являются объектами. Как говорит Википедия, системы сущностей и компонентов являются образцом архитектуры программного обеспечения для моделирования общих объектов.
NO. И я удивлен, как много людей проголосовало за иное!
парадигма
Он ориентирован на данные, иначе говоря, управляемый данными, потому что мы говорим об архитектуре, а не о языке, на котором он написан. Архитектуры - это реализации стилей программирования или парадигм , которые обычно можно обойти нежелательно на данном языке.
Функциональная?
Ваше сравнение с функциональным / процедурным программированием является уместным и значимым сравнением. Однако обратите внимание, что «функциональный» язык отличается от «процедурной» парадигмы . И вы можете внедрить ECS на функциональном языке, таком как Haskell , что и сделали люди.
Где сплоченность происходит
Ваше наблюдение является актуальной и спот- :
ECS / ES не является EC / CE
Существует разница между компонентно-ориентированными архитектурами, «Entity-Component» и «Entity-Component-System». Поскольку это развивающийся шаблон проектирования, я видел, что эти определения используются взаимозаменяемо. Архитектуры «EC», «CE» или «Entity-Component» определяют поведение компонентов , в то время как архитектуры «ES» или «ECS» определяют поведение систем . Вот некоторые статьи ECS, обе из которых используют вводящую в заблуждение номенклатуру, но дают общее представление:
Если вы пытаетесь понять эти термины в 2015 году, убедитесь, что чья-то ссылка на «Систему компонентов сущностей» не означает «Архитектура компонентов сущностей».
источник
Системы компонентов объектов (ECS) могут быть запрограммированы ООП или функциональным образом в зависимости от того, как определена система.
ООП способ:
Я работал над играми, где сущность была объектом, состоящим из различных компонентов. У сущности есть функция обновления, которая изменяет объект на месте, вызывая update для всех его компонентов по очереди. Это явно ООП в стиле - поведение связано с данными, и данные являются изменчивыми. Сущности - это объекты с конструкторами / деструкторами / обновлениями.
Более функциональный способ:
Альтернативой для объекта являются данные без каких-либо методов. Эта сущность может существовать сама по себе или просто быть идентификатором, который связан с различными компонентами. Таким образом, возможно (но обычно это не делается) быть полностью функциональным и иметь неизменные сущности и чистые системы, которые генерируют новые состояния компонентов.
Кажется (из личного опыта), что последний путь набирает обороты и по уважительной причине. Отделение данных объекта от поведения приводит к более гибкому и многократно используемому коду (imo). В частности, использование систем для обновления компонентов / объектов в пакетах может быть более производительным и полностью исключает сложности обмена сообщениями между объектами, которые мешают многим ООП-ECS.
TLDR: Вы можете сделать это в любом случае, но я бы сказал, что преимущества хороших систем компонентов сущности вытекают из их более функциональной природы.
источник
Компонентные системы объектов, ориентированные на данные, могут сосуществовать с объектно-ориентированными парадигмами: - Системы компонентов поддаются полиморфизму. - Компоненты могут быть как POD (обычные старые данные), так и объектами ALSO (с классом и методами), и все это по-прежнему «ориентировано на данные», при условии, что методы класса компонентов обрабатывают только данные, принадлежащие локальному объекту.
Если вы выберете этот путь, я рекомендую вам избегать использования виртуальных методов, потому что, если они у вас есть, ваш компонент больше не является чисто компонентными данными, плюс эти методы стоят дороже - это не COM. Как правило, ваши классы компонентов должны быть чистыми от любых ссылок на внешние объекты.
Примером может служить vec2 или vec3, контейнер данных с некоторыми методами для обработки этих данных, и ничего более.
источник
Я считаю, что ECS принципиально отличается от ООП и склонен рассматривать его так же, как вы, более близкий к функциональному или особенно процедурному по своей природе с очень четким разделением данных от функциональных возможностей. Есть также некоторое подобие программированию, имеющему дело с центральными базами данных. Конечно, я худший человек, когда дело доходит до формальных определений. Меня интересует только то, как обстоят дела, а не то, чем они концептуально определены.
Я предполагаю что-то вроде ECS, где компоненты агрегируют поля данных и делают их общедоступными / глобально доступными, сущности агрегируют компоненты, а системы обеспечивают функциональность / поведение этих данных. Это приводит к радикально сложным архитектурным характеристикам, которые мы обычно называем объектно-ориентированной кодовой базой.
И, конечно, есть некоторые размытые границы в том, как люди проектируют / внедряют ECS, и идут споры о том, что именно представляет собой ECS. Все же такие границы также размыты в коде, написанном на том, что мы называем функциональными или процедурными языками. Среди всей этой нечеткости фундаментальная константа ECS с отделением данных от функциональности кажется мне гораздо ближе к функциональному или процедурному программированию, чем ООП.
Одна из главных причин, по которой я не думаю, что полезно считать ECS принадлежащим к классу ООП, заключается в том, что большинство практик SE, связанных с ООП, вращаются вокруг стабильности общедоступного интерфейса с функциями моделирования общедоступных интерфейсов , а не с данными. Основная идея заключается в том, что основная часть общедоступных зависимостей направлена на абстрактные функции, а не на конкретные данные. И из-за этого ООП, как правило, делает очень дорогостоящим изменение фундаментального поведения при проектировании, в то же время удешевляя изменение конкретных деталей (таких как данные и код, необходимые для реализации функциональности).
ECS радикально отличается в этом отношении, учитывая, как все взаимосвязано, поскольку основная часть общедоступных зависимостей направляется к конкретным данным: от систем к компонентам. В результате любая практика SE, связанная с ECS, будет вращаться вокруг стабильности данных , потому что наиболее общедоступные и широко используемые интерфейсы (компоненты) на самом деле являются просто данными.
В результате ECS позволяет очень легко выполнять такие вещи, как замена движка рендеринга OpenGL на DirectX, даже если эти два реализованы с радикально отличающимися функциональными возможностями и не имеют одинаковых конструкций вообще, при условии, что и движок DX, и GL иметь доступ к таким же стабильным данным. Между тем это было бы очень дорого и потребовало бы переписывания нескольких систем для изменения, скажем, представления данных a
MotionComponent
.Это очень противоположно тому, что мы традиционно связываем с ООП, по крайней мере, с точки зрения характеристик связи и того, что составляет «открытый интерфейс» и «частные детали реализации». Конечно, в обоих случаях «детали реализации» легко изменить, но в ECS изменение данных требует больших затрат (данные не являются деталями реализации в ECS), а в ООП - изменение функциональности, которое стоит изменить. (дизайн функций не является деталью реализации в ООП). Так что это совсем другое представление о «деталях реализации», и одно из главных обращений ко мне с ECS с точки зрения обслуживания было то, что в моей области, данные, необходимые для того, чтобы что-то делать, было проще раз и навсегда стабилизировать и спроектировать правильно, чем все различные вещи, которые мы могли бы сделать с этими данными (которые будут меняться все время, когда клиенты меняют свое мнение и приходят новые предложения пользователей). В результате я обнаружил, что затраты на обслуживание резко упали, когда мы начали направлять зависимости от абстрактных функций к необработанным, центральным данным (но все же с осторожностью относимся к тому, какие системы обращаются к каким компонентам, чтобы обеспечить возможность сохранения инвариантов в разумной степени, несмотря на то, что все данные концептуально существуют глобально доступный).
И в моем случае, по крайней мере, SDK ECS с API и всеми компонентами фактически реализован на C и не имеет никакого сходства с ООП. Я нашел C более чем достаточным для такой цели, учитывая присущий ей недостаток OO в архитектурах ECS и желание иметь архитектуру плагинов, которая может использоваться самым широким диапазоном языков и компиляторов. Системы по-прежнему реализованы на C ++, поскольку C ++ делает их там очень удобными, и системы моделируют большую часть сложности, и там я нахожу применение многим вещам, которые можно рассматривать ближе к ООП, но это для деталей реализации. Сам архитектурный проект все еще напоминает очень процедурный С.
Так что я думаю, что несколько сбивает с толку попытка сказать, что ECS является OO по определению. По крайней мере, основы делают вещи, которые на 180 градусов поворачиваются от многих фундаментальных принципов, обычно связанных с ООП, начиная с инкапсуляции и, возможно, заканчивая тем, что считается желаемыми характеристиками связи.
источник