Привет разработчики! В этом топике будут выходить devlog’и моего самого сложного проекта. Статья будет вводной, а процесс разработки вы сможете увидеть в комментариях.
Почему категория “Полезное”? Думаю, кому-то могут в будущем пригодиться некоторые подходы.
Библиотека создаётся под экосистему Roblox Studio на языке luau. Автор не является профессионалом, поэтому может допускать ошибки в теоретической базе.
Оставляйте комментарии в топике. Буду рад любым исправлениям и идеям по улучшению проекта.
Введение
ECS — Entity-Component System стал альтернативой классическому Объектно-Ориентированному подходу. В процессе разработки программисты поняли, что наследование не такой уж и идеальный инструмент. К сожалению, возможность создавать множество похожих сущностей по поведению чревато серьёзной связанностью кодовой базы.
Предположим, вы создаёте игру в стиле Car Crushers 2. Есть базовые классы колёсного и водного транспорта. От них наследуются непосредственно классы конкретных видов, например, машин. И так далее.
В какой-то момент геймдизайнер просит создать колёсный транспорт с возможностью плавать. Программисту приходится реализовывать новый базовый класс колёсно-воздушного транспорта. Пока всё хорошо и ECS вам не нужен!
Теперь представьте, что таких обращений сотни. Кодовая часть игры начинает распухать классами. А вот это уже неприятно. Растут зависимости. Любая новая интеграция повышает время и стоимость разработки.
Поэтому в конце 90-х годов была предложена новая концепция. Теперь классы не занимаются хранением и обработкой информации. Данные разделяются в отдельные группы. Так появилась Entity-Component парадигма. Со временем она развилась до привычного современного представления. Обсудим базовые понятия.
Entity — сущность. В простом понимании — коробка, которая хранит в себе какие-то состояния. В нашем случае ссылки на компоненты.
И пусть название вас не вводит в заблуждение: сущностью может быть что угодно. От NPC до абстрактной части кода. Даже component в каких-то случаях — entity. Например, такой подход использует мощная библиотека flecs на C++.
Component — компонент. Место хранения состояний entity. Каждый компонент должен хранить строго определённый тип данных.
Не рекомендуется в компонент под int-числа класть boolean-значения.
System — системы. Функции или классы, которые работают с компонентами: добавляют, читают, изменяют и удаляют.
Вернёмся к нашему многострадальному примеру. Теперь мы можем представить весь транспорт как отдельные entity. Внутри положим component’ы, которые будут определять тип транспорта, скорость, физические показатели и прочее. Напишем функции обработчики.
Поздравляю, мы на простом и абстрактном уровне решили проблему. Если не ощутили кайфа — возможно, ECS вашей игре не нужен.
Все entity хранятся в world. Название говорит за себя. В мире хранится вся информация. Обращения к сущностям производится по их ID. В графическом представлении мир выглядит как таблица. Строки — entity. Столбцы — component. Теперь мы можем пройтись по строке и посмотреть, какими состояниями владеет.
В целом, вся работа с ECS-библиотеками и фреймворками сводится к множественным итерациям. Со временем программисты наткнулись на подводный камень…
Data-Oriented Design
Программисты, которые владеют какими-то знаниями в области C++, наверняка знают про мероприятие CppCon. Давайте посмотрим самое популярное видео канала, куда загружают выступления лучших гиков:
Советую, кстати, посмотреть ![]()
Разработчики поняли, что их кодовая база работает слишком медленно с большими массивами данных. Причина кроется в основах computer science. Авторам огромных ECS-библиотек пришлось подстраиваться под новые правила игры.
Видите ли, процессор очень не любит работать с оперативной памятью. Оно и не мудрено. Камню приходится выполнять сотни тактов, чтобы дотянуться до кризисной плашки. Поэтому инженеры придумали КЭШ.
В архитектуре Intel выделяют три уровня: L1 — самый быстрый и маленький, L2 – медленнее и больше, L3 — самый медленный и большой. К слову, самыми быстрыми хранилищами данных у процессора выступают регистры. Данных в них вмещается немного.
В предыдущих версиях ECS-библиотек все компоненты и сущности были размазаны по всей памяти. Процессору приходилось тратить слишком много времени на обращения. При итерациях это убивало напрочь всю быстроту подхода.
Программисты стали думать: как расположить данные плотнее друг к другу в памяти? Что эффективнее: Array of Structs или Struct of Arrays?
На эти вопросы пришлось отвечать и мне при разработке библиотеки! Об этом — в следующем devlog.

