Добавлен , опубликован
Не так давно наткнулся на такой подход программирования в играх как ECS (Entity Component System). Далее начал читать статьи и смотреть различные ролики по этой теме. Из названия понятно что это разделение на сущности, компоненты и системы. Но почему он становится более предпочтительным в разработке игр нежели всем известный ООП с его подходами?
Для того чтобы это понять, нужно вспомнить как ваши данные ложатся в памяти. В обычном ООП мы объявляем множества полей в объекте и инкапсулируем логику внутри самого объекта. Из-за этого такие объекты хранятся в памяти разрозненно, соответственно при попадании в память процессора, которая является самой быстрой, обрабатываются дольше из-за того что ей нужно каждый раз загружать новый блок данных из разных мест.
Чтобы данные лежали плотно и при работе программы начинали переиспользоваться в кэше процессора, можно воспользоваться дизайном ориентированном на данных (Data-Oriented Design), по сути это чем-то похоже на базы данных, только в оперативной памяти.
Как раз это и использует ECS. Там сущности являются просто идентификаторами, компоненты структурами данных без логики, которые можно добавить и удалить для любой из сущностей, и системы для обработки логики, где итерации происходят по определённым компонентам. Например, игрок является сущностью, а его скорость, позиция и жизни компонентами, движение игрока будет системой, которая итерируется по компонентам скорости и позиции. Данный подход делает наш код практичным и переиспользуемым.

Я прошёлся по верхам и не рассказал как это реализуется, потому что существуют разные подходы. Вот несколько ссылок на различные статьи по этой теме:
Entity Component System FAQ
Let's build an Entity Component System from scratch (part 1)
Let's build an Entity Component System (part 2): databases
Building an ECS #1: Where are my Entities and Components
Building an ECS #2: Archetypes and Vectorization
Building an ECS #3: Storage in Pictures
Опрос: Слышали об ECS?
1. 
Впервые слышу
2. 
Слышал, но не применял
3. 
Встречал на практике
4. 
Писал свою реализацию
`
ОЖИДАНИЕ РЕКЛАМЫ...
16
Минус png с черным текстом на темной теме сайта
Загруженные файлы
Ответы (1)
30
Но почему он становится более предпочтительным в разработке игр нежели всем известный ООП с его подходами?
И почему же?
Ответы (1)
16
nazarpunk, ниже по тексту написал. То что объекты и его иерархия никак не подразумевает хранение плотно в памяти, потому что куча ссылок и наследований других полей. В DOD подходе мы реализуем данные так чтобы они хранились плотно в массивах и обход по ним происходит быстрее, за счёт попадания в кэш процессора и повторного переиспользования без необходимости заново загружать в память процессора, какого блока памяти.
30
Данный подход делает наш код практичным и переиспользуемым.
А методы для работы с этими сущностями в код не входят?
Ответы (1)
16
nazarpunk, входит, это системы. Например как в Unity есть метод update, в котором пишут какую-то логику. Получается что ты в таком методе проходишься по массиву нужных тебе компонентов, которые есть у сущностей, и от этого пишешь логику.
30
Например, игрок является сущностью, а его скорость, позиция и жизни компонентами, движение игрока будет системой, которая итерируется по компонентам скорости и позиции. Данный подход делает наш код практичным и переиспользуемым.
Ужасное ООП
class Unit {
	vec3 position;
	vec3 speed;

	void move(){
		//...
	}
}
Прекрасный ECS
struct Position {
	vec3 position;
}

struct Speed {
	vec3 position;
}

class Unit {
}

struct UnitHolder {
	Unit unit;
	Position position;
	Speed speed;
}


void moveUnit(UnitHolder unit){
		//...
}
Ответы (10)
38
nazarpunk, не, там фича в другом.
Скорее
Решение А
agentSKucheyGovna[i]
Решение Б
agents[i]
worldState[i]
kuchaGovnaSpellov[i]
...
Угадай в каком решении быстрее сделать обходы и умножения векторов много раз в секунду
30
ScorpioT1000, а как слинковать сущности между собой? Например нанести юниту урон от столкновения?
16
nazarpunk, скорее у юнита будет компонент, отвечающий за его хит бокс и у тебя будет система, которая проходится по сущностям у которых есть какой-то архетип компонентов, как скорость, позиция, хп, хит бокс. И при условии что у каких-то двух объектах расстояние близкое, то наносим урон в зависимости от скорости отнимая от текущего хп
30
bifurcated, а каким образом связаны собственно позиции и хп. Это же по сути разные сущности. Ну или более банальный пример. У нас физический движок и нужен маятник Ньютона? Как передать импульс ровно последнему шарику?
Загруженные файлы
16
nazarpunk, позиция и хп это компоненты, данные которые ты добавляешь в сущности, а сущность это просто ссылка (id) на какой-то набор этих компонентов. Тут отношение один ко многим.
30
Угадай в каком решении быстрее сделать обходы и умножения векторов много раз в секунду
А насколько у нас тесные связи? Вот допустим у нас есть система аур. Одна аура распространяет пониженную гравитацию в сфере. Другая распространяет вектор гравитации к своему центру. Третья убирает коллизии на своём радиусе. Как нам поможет ECS?
Ну или вообще по классике. Есть у нас дерево. Как удалить родителя не оставив висячих ссылок в пустоте? В ООП это разрулится деструкторами. А в ECS?
30
позиция и хп это компоненты
Каким образом они слинкованы? Если при получении достаточного урона юнит умер, то его вектор не передастся следующему юниту. Как это делается?
16
nazarpunk, зависит от реализации, например, это на прямую хранить в мапе по id сущности массив его компонентов, компоненты можно добавлять и удалять. Ты наверное не понял, у каждой сущности свой инстанс этих компонентов.
38
nazarpunk, модуль коллизий хранит массив всех текущих столкновений - это 2 индекса мешей/примитивов, нормалей и глубины проникновения
Из меша узнаем, чей это меш, после чего идем в любой компонент этого объекта
38
nazarpunk, а зачем тебе дерево, прямая линковка это несортированный список. Удаление = перемещение последнего элемента на место удаленного. Сортировки и деревья идут уже с индексами этого списка как пристройки
20
Разве это не то как реализовано ООП в vJass? Там как раз instance структуры это всего лишь индентификатор к массивам.

Я вот не совсем представляю ECS для использования с БД, получается каждое обращение к компоненту сущности это новый запрос в БД? Ну мб я че-то не понял. Мало инфы как-то, ссылки я видел, но пост будто бы ни о чем. Перенос бы уже информацию сюда и структурировал.
Ответы (4)
30
KaneThaumaturge, как я понял, идея в том чтоб убрать автоматику из жтого вашего ООП и вручную более оптимально ложить структурированные данные в память.
16
KaneThaumaturge, используя jass/vJass я из синтаксиса языка максимум массивами пользовался. Статью писать лень, а тут темы появились и решил так кратко пройтись
30
bifurcated, ну, на грязножассе нет нормального ООП, посему и сравнивать с ECS некорректно.
31
Делаю свой текущий проект на ECS (Entitas), и честно говоря, какого-то дичайшего восторга не испытываю. Концепция, безусловно, интересная. При работе с огромным количеством юнитов - даже незаменимая. Однако на маленьких масштабах я бы не сказал, что прям супер полезная.
Одна из фишек - одна и та же сущность может одновременно быть несколькими разными объектами, потому что набор висящих на ней компонентов будет по-разному интерпретироваться разными системами. Но мне, по факту использования, эта фишка пока особо не пригождалась.
Лично мне в душу запахло именно структурирование кода - разбиение его на маленькие системки, и их последовательный вызов. Да, системки вот прям маленькие - не больше 50 строк, а в среднем - вообще по 20-30 строчек.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.