Pull to refresh

Comments 15

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

ну и если захочется кинематики делать выделил бы какието паттерны кодом отдельно, например выбор-увеличение, выбор в нужный момент и он идёт как-то и поворачивается ) анимации вообще класс

Во всех примерах Поведение содержит ссылку на Сущность, то есть на каждый экземпляр Состояния создается по экземпляру Поведения?

Что сильно проигрывает ECS, где одна Система обрабатывает все Компоненты.

В фреймворке предусмотрены механизмы, которые либо взаимодействуют с миром и получением сущностей по фильтрам, либо работают с пулом сущностей. Эти механизмы позволяют обрабатывать набор похожих сущностей, используя единое поведение для всех.

Да, всё верно. У каждой сущности может быть свой набор состояний и поведений. Если в игре, например, есть пять персонажей, то у каждого будет своя механика перемещения. Такой подход удобен тем, что, скажем, если нужно наложить эффект яда, ты просто добавляешь ещё одно поведение конкретному персонажу — без изменения остальной логики.

Преимущество индивидуального поведения заключается в возможности использовать реактивное программирование и слушать изменения данных через подписку.

на низком уровне можно пойти дальше, чтобы отвязать геометрию - рендер от логик, просто ассоциативно создаём структуры созданий, в созданиях указатель на поведение в ней типы поведений, вуаля вы оптимизировались, но это на С++, на сишарпе около того же, но чутка по другому

тогда проход будет по позициям просто тоесть ассоциативный рендеринх, ну придётся хранить айди геометрии ну или указатель на геометрию хранить тоже пока думаю )

ну или на первое время можно побегать и с большущей структурой тогда проход все равно будет 1 просто структура большая, они в обоих случаях превращаются в 1 пулл(созданий) на уровне, ну у меня получилось 1 массивом организовать

Скорее ООП с элементами ECS. Подход гибридный. Он строго разделяет данные и логику, но при этом поведение крепится к каждой сущности и обрабатывает объекты вместо структур. Такой подход позволяет делать данные полиморфными и управлять индивидуально сущностью в отличие от ECS

А для IVariable типа int в проекте генерируются экстеншны для всех сущностей с таким филдом? Получается будет список из всех методов от всех данных в коде на каждый тип так? Если так, то это быстро станет неюзабельным, тк по имени филда данных будет непонятно, совместим ли он с конкретным behaviour или нет.

IVariable — это интерфейс атомарного элемента, он сам по себе не генерируется.
Кодогенерация создаёт ключи (accessors), которые возвращают конкретный тип данных, связанный с сущностью.
То есть экстеншены не плодятся для всех IVariable<int> подряд, а жёстко типизированы под конкретные атомы.

За счёт этого список методов остаётся компактным и понятным — ты сразу видишь только релевантные поля и поведение, без дублирования по типам.

Подробности можно посмотреть в статье, где разбирается процесс кодогенерации: https://github.com/StarKRE22/Atomic/blob/main/Docs/Entities/EntityAPI/Manual.md.

Ох...

Я очень ценю самостоятельных авторов и их эксперименты, новые идеи и свободные библиотеки.
Но ваш подход видится мне настолько фундаметнально ошибочным сразу на стольких направлениях, что у меня даже немножко горит.

Но постараюсь описать конструктивно, все же фидбек важен.

Итак начнем.

Сначала небольшой дисклеймер. Я считаю ECS довольно элегантной и крутой идеей, но очень специализированной архитектурой. Плюсами является скорость и хранение стейта (что почти за бесплатно дает сохранения/снапшоты/повторы и работу по сути), а так же плоская структура. Минусами - сложность, большее количество кода и очень жесткие требования по организации и архитектуре для хорошего кода (ровно противоположное от того, что говорят апологеты). Из-за разделения данных и кода, вторичной системы индексирования (индексы/сущности вместо ссылок в памяти) код очень сложно читать и понимать, а так же дебажить (хотя прозрачное состояние тут плюс). Люди неоднократно говорили мне, что им так проще, но практика совместной разработки показывала, что код легко превращается в ад. 2 основных проблемы - из-за разделения операций на действия и сущности для понимания поведения какого то объекта (скажем персонажа с оружием) нужно собрать в голове в правильном порядке все сущности и операции с ними, потому что они размазаны по проекту. И аналогично, для организации иерархии объектов (а они естественны) необходимо собирать эти деревья по ссылочкам руками - юнит, в нем индекс пушки, из нее сущность пушки в ней компонент заряда, в нем индекс заряда из нее сущность заряда из нее параметры компонента с типом патрончика - как то так.

Ваш паттерн фундаментально следует логике ECS в смысле разделения данных и кода, соответственно почти все части этой критики применимы и к вашему фреймворку.

Отказ от структуры Unity ведет к довольно большому количество Boilerplate кода (создание и описание сущностей, файлы поведения + накладные расходы на описание инсталлеров и мапперов), к управлению действиями нужно привыкать, вы так же теряете серьезную часть редактора (объекты можно писать в таком стиле, чтобы их могли использовать геймдизайнеры, их можно было комбинировать с существующими и сторонними компонентами самой Unity.

Ну и производительность.
Во первых, у вас каждое обращение каждого поведения достает компоненты. Даже если бакеты достаточно шустрые, там боксинг/анбоксинг с приведением. Во вторых само по себе доставание - операция более дорогая чем доступ по ссылке.
Mono Behaviour все считают очень медленными, что конечно правда по сравнению с plane объектами и специализированными решениями, но совершенно не правда в целом. Обычно проблемы вызваны неуемным использованием самых разнообразных компонентов.
Если вы разделяете логику и представление (а вы насильно делаете это, в этом ведь суть фреймворка), то вы, аналогично многим ECS решениям, просто заставляете разработчика задумываться о том, сколько и чего он использует. Но это не корректное сравнение - в таком случае нужно сравнивать с чистыми plane объектами (не наследниками MonoBehaviour, а обычными структурами и классами), использующими MB только как визуализацию.
Я конечно свечку не держал, может у вас есть цифры, но просто по коду двух основных гирь - регистрации и доступу к компонентам, Я не вижу как этот подход может быть производительнее. Плюс использование интерфейсов может мешать компилятору резолвить типы ваших сущностей к реальным типам, у вас много приведений к object

У меня есть ощущение, что многие люди разочаровались в ООП, потому что приняли его слишком серьезно, вот и у вас - сам код фреймворка написан по всем стандартам, с разделением всего на интерфейсы, стройной иерархией. Но чудовищными partial классами, напрочь ломающими инкапсуляцию и делающие чтение фреймворка адком.

По сути, если хочется достигнуть подобного минималистичными методами, можно просто использовать анемичные объекты - делать все объекты с public полями, собирать все действия в аналоги систем (поведений, не суть) - будет ровно та простота, которую вы предлагаете. И не нужно строить костыли для производльного доступа к виртуальным полям просто чтобы игнорировать сложности классического ООП которые могут вам мешать (но которые на самом деле не требуются)

Единственное, в чем ваша абстракция могла бы помочь - это если бы вынести ее на уровень представления, дать возможность геймдизайнерам собирать объекты из свойств и поведений с визуальным редактором, но приличной производительностью.
ГД безусловно будут писать треш и ересь, но будут очень рады такому инструменту.
Это иллюзия, что такая организация спасает от архитектуры. Архитектура - это прежде всего связь между вашими сущностями, а не ECB. Такую же архитектуру придется продумывать, только в рамках вашей системы, без инструментов для работы с ней.

В моем представлении вы выплеснули с водой младенца - никаких преимуществ ECS, но все его недостатки со своими собственными.
Я могу быть разумеется не прав, и конкретно для вас это может быть хорошим подходом. Но предостерегаю.

Спасибо большое за развёрнутый и честный фидбек! Я действительно ценю, что вы нашли время так подробно разобрать Atomic.

Вы затронули несколько ключевых тем — попробую прокомментировать их коротко по сути.

1. Про сходство с ECS

Да, вы правы. Atomic действительно унаследовал часть идей ECS, но основная цель — не оптимизация под DOD, а упрощение разработки игры в виде возможности быстро собирать механики из атомарных элементов без проектирования ООП иерархий.

Можно сказать, что это “ECS без конвейера”, где внимание сосредоточено не на кешах и батчах, а на композиции данных и логики.

2. Разделение данных и логики

Вы верно заметили, что разделение данных и логики может повысить когнитивную сложность при чтении кода, особенно если механика разнесена по нескольким behaviour’ам.

Atomic решает это за счёт единообразной структуры ESB (Entity-State-Behaviour) и кодогенерации, которая делает доступ к данным явным и типобезопасным. Вместо поиска по строковым ключам используем entity.GetMoveSpeed(), а вместо “магических” связей — декларативные инсталлеры.

Это не отменяет сложности — но снижает её до уровня «читаемого procedural code».

3. Boilerplate и Unity-интеграция

Да, количество декларативного кода выше, чем в MonoBehaviour-подходе, и это осознанный компромисс. Atomic — это не «ещё один DI-фреймворк», а средство разработки игры в едином паттерне. Boilerplate компенсируется единообразием. Все сущности, UI, контексты и системы собираются одинаково, что в долгосрочной перспективе уменьшает энтропию проекта.

4. Производительность

Вы абсолютно правы, что каждое обращение к данным сущности дороже, чем прямой доступ к полю. Вместе с тем, большинство атомарных сущностей разрешают ссылки один раз при Init(), а дальше работают с ними напрямую без повторных обращений и боксинга.

Сравнение с чистыми C#-объектами справедливо, так как Atomic не претендует на скорость ECS, его цель — структурная производительность, когда добавление механик не замедляет команду разработки.

5. Частичный отказ от ООП

Тут согласен. Фреймворк сознательно ломает классическую инкапсуляцию. Это цена за “атомарность” — возможность динамически собирать и разбирать сущность без знания её внутренней структуры. Но при этом Atomic сохраняет полиморфизм и строгую типизацию интерфейсов, что отличает его от “анемичных объектов” в procedural-подходе.

Резюме

В итоге вы правы: Atomic — не “универсальное решение”, но и не попытка заменить ООП или ECS. Это экспериментальная архитектура для быстрой сборки игрового поведения и изоляции симуляции от Unity. Кому-то она покажется лишней абстракцией, а кому-то удобным слоем над чистым C#. Но ваш отзыв помог чётче осознать эти границы. Спасибо за это!

Возможно кому то подход понравится. Если планируете развивать - подумайте о штуках, которые могут улучшить привлекательность подхода - например, сохранение / загрузка из коробки (если у вас есть централизованный список сущностей и компонентов - должно быть тривиально), инструменты визуализации, возможно - инструменты визуального программирования.

Таким подходом можно, например, «превратить боевого персонажа в овцу», просто изменив набор его данных и логики без пересоздания объекта или сложных зависимостей.

Не выйдет.​ Придётся ещё вытащить CharacterViewInstaller и SheepViewInstaller (разумеется, это MonoBehaviour), дернуть Uninstall/Install и молиться, что view‑поведения овцы синхронизированы с логикой…​

По сути бехи жёстко прибиты к данным, только неявно.​ Вьюбехи так же магически связаны с бехами.​ Всё это ради гибкости быстро-собирающегося конструктора, но такой конструктор так же быстро и рассыпается.​

И главное - на практике такая гибкость почти не нужна: боевой персонаж превращается в овцу заменой сущности, а не переконфигурацией.

Чё там, юнити ещё не перешёл на дотнет? Все ещё на моно?

Sign up to leave a comment.

Articles