Comments 42
Очень верно сказано про возможность оптимизации отдельных систем в без какого либо ECS.
Вообще, сама идея ecs нарушает заповедь о преждевременной оптимизации.
Нарушеним этой заповеди страдают в основном начинающие программисты и по этому поводу можно сказать пару слов, ежели вдруг кто из таковых будет это читать. Выбор инструмента позволяющего сразу писать быстродействующий код - это очень соблазнительная идея, но благими намерениями, как известно выстелена дорога в ад. В геймдеве укоренилось особое значение слова оптимизация. Игровой разработчик и игроки, а следом за ними и разработчики прочих сфер, бывшие когда-то игроками, говорят "оптимизация", понимая оптимизацию по быстродействию и забывают о том, что оптимизация бывает и по другим параметрам. Конечно, разработка програмного обеспечения - довольно молодая отрасль, но если до чего и допёрло человечество за время её развития, так это до того, что код в первую очередь должен быть не быстрым, а понятным и обслуживаемым, и именно по этому параметру он должен оптимизироваться. Существует целая математическая теорема, согласно которой система в общем случае может быть оптимизирована только по одному параметру и когда мы выбираем быстродействие, мы сразу же задвигаем удобство работы с кодом в дальний угол. Худшее, что может сделать разработчик для того, чтобы сделать хороший продукт - возненавидеть собственный код в процессе работы над ним.
Если код будет напоминать не кусок госсэ, а попендикулярное произведение искусства, в момент когда настанет необходимость увеличивать быстродействие, это можно будет сделать легко и уместно. В плохом же коде таковые попытки могут привести к обвалу всего здания
Я так понимаю речь про "ROC theorem: Readable, Optimised and Correct code."? Если да, то это какой-то левый сайт, где нет никакой математики и доказательств, поэтому хз кто осмелился назвать это теоремой. Максимум субъективное рассуждение. Другой "теоремы" найти увы не смог.
Заповедь о преждевременной оптимизации это не заповедь и не фундаментальный закон, а совет, который много кем критиковался и который нельзя применять или использовать как оправдение в большом количестве кейсов.
Да, не нужно оптимизировать прототипный или временный код, но нужно разделять оптимизацию и непессимизацию ((с) Кейси Муратори). Если библейские заповеди говорят мне написать какую-то медленную шляпу, когда я могу с теме же усилями написать что-то быстрее и не потерять в читаемости, либо даже потерять, но получить большой буст к перфе, то мой долг как программиста не следовать заповедям и догмам, а сделать так, чтобы у юзера был нормальный фпс. Мы пишем игры в конце концов.
В любом случае ECS не про оптимизацию, хотя он и даёт буст перформанса из коробки. Да, даёт бесплатно, практически без минусов, вернее плюсы в виде гибкости и готовой архитектуры перевешивают минусы в контексе игр. Сама мысль, что мы не можем получать всё и сразу, либо получать больше, чем у нас есть сейчас, предполагает, что у нас идеальные инструменты под задачу, когда это явно не так.
Понятия не имею, что это за сайт, но нет... теорема об одном критерии существует в теории оптимизации, хотя она довольно очевидна и не то чтобы требует доказательств. Её можно найти в книжках по оптимизации и её приложениях, например в теории оптимального управления. Для решения проблемы принципиальной однокритериальности существует раздел многокритериальной оптимизации, область изучения которого по сути сводится к вопросу, как из многих критериев получить один с наименьшими потерями для каждого из исходных критериев
является специализированной высокопроизводительной архитектурой
Да нет же, не является ECS "специализированной высокопроизводительной архитектурой". "Специализированным высокопроизводительным" может быть фреймворк, например, таким можно считать DOTS от Unity, который крутится вокруг ECS, но сам подход нельзя называть так, ибо разделение данных и логики само по себе НИКАК не говорит про производительность. И в этом моя главная претензия ко всем нелюбителям(и половине любителей) ECS и именно это сподвигло меня написать статью, на которую вы ссылаетесь в самом начале. ECS это в первую очередь удобство разработки благодаря отделению данных от логики, производительность вторична и оооочень сильно зависит от фреймворка. В то же время какой-нибудь DOD(Data-Oriented-Design, реализация ECS вполне может соответствовать DOD) уже - да, разговаривает про производительность.
Статью пока дальше не читал(судя по оглавлению там только тейк про производительность другими средствами), но обязательно прочитаю как появится свободное время, так что ждите других комментов :)
Это отчасти правда, но я не согласен с этим потому, что изначально эта архитектура была ассоциирована с решением проблем производительности.
Cама концепция систем сосредоточена на пакетной обработке компонентов, иначе их бы можно было бы назвать командами и применять к отдельной паре компонентов. Есть известная цитата про нарезку хлеба (с которой я не согласен).
Вторичная система индексации, когда у вас есть Entity и это просто индекс, так же направлена на это, иначе можно было бы просто использовать ссылку на объект entity.
Все это вместе дает свою философию доступа к объектам, которая отличается от просто доступа по ссылке.
Если бы речь шла только про декомпозицию и отделение данных от логики, вы бы могли (и можете) организовать это на обычных компонентах unity + системах, в этом смысле она и так entity-component.
Но в целом, значительная часть моей критики и направлена на то, что ультрадекомпозиция и отделение данных от логики по умолчанию - это плохое решение, которое в долгосрочной перспективе сделает проект крайне сложным для обслуживания.
Так что да, Я критикую и эту часть тоже)
изначально эта архитектура была ассоциирована с решением проблем производительности
Ассоциировать её с решением проблем производительности начали только после того как Unity занялись популяризацией DOTS(скорее всего подсмотрев у фростбайта). До этого все просто пользовались гибкостью.
Я работал в одной конторе, где свой самописный ECS под Unity появился задолго до Entitas(то есть вообще до ECS-хайпа) и там это было обусловленно именно гибкостью разработки и оно было реально гибко. Собсно я с тех пор и полюбил ECS всем сердцем. Жаль проект не взлетел из-за в том числе проблем с производительностью фреймворка, ибо он был полностью на рефлексии и достаточно кривоват(но крут в плане возможностей).
Все это вместе дает свою философию доступа к объектам, которая отличается от просто доступа по ссылке.
Философия заключается лишь в отделении данных от логики, реализовать можно по разному, в том числе и на ссылках и с иерархией классов(да, такое я тоже видал).
Если бы речь шла только про декомпозицию и отделение данных от логики, вы бы могли (и можете) организовать это на обычных компонентах unity + системах, в этом смысле она и так entity-component.
Спору нет, можно. Если в одном монобехе открытые данные, а в другом логика, то это вполне себе ECS и оно будет иметь все плюсы ECS(хотя зависит от реализации). ECS фреймворки нужны для удобства фильтрации и итерации.
ультрадекомпозиция
Ультрадекомпозиция это лишь один из взглядов на ECS, совсем не обязательно делить всё до атомарного уровня(а скорее даже не стоит)
отделение данных от логики по умолчанию - это плохое решение, которое в долгосрочной перспективе сделает проект крайне сложным для обслуживания
На моём опыте на дальней перспективе как раз классическая ООП иерархия или КОП доставляют больше жжения в жопе, чем ECS, в плане сложности добавления новых фич
В моем опыте скорее аккуратный КОП является близким к идеалу.
Но есть несколько важных нюансов, в частности размер команды, количество в ней ГД и то, как принято работать с игрой с точки зрения ГД - есть ли полноценный левел дизайн и работают ли технические художники и неспециалисты с уровнями и префабами. Либо они допущены только до конфигураций.
В первом случае сосредоточиться на правильной декомпозиции и удобстве для последних на порядок важнее любой архитектуры и стандартные компоненты, ну ОК.
Глубокие иерархии (наследования) однозначно зло. А вот иерархии объектов очень нужны (в смысле когда один класс использует напрямую другие - отряд - юнит - оружие - пуля).
В этом контексте обычные способы декомпозиции предлагаемые ECS (типично иметь компонент-позицию, здоровье и компоненты-флаги, к примеру) превращают проект в сложную комбинацию эффектов, понять которые крайне сложно.
Из описаний выше с Match-3 примером как раз потребовалось осознать, что ECS подход сам по себе не поможет. А помогла логическая декомпозиция того, из чего состоит реальная фишка на состояние, эффект и взаимодействие. Условно на триггер и эффект, которые можно сочетать независимо.
Без этого код рос условиями каждый-к-каждому в том числе в ECS рос бесконтрольно и рожал много ошибок. Классический ООП тоже тут в общем то так же споткнулся бы.
Сейчас Я бы лучше использовал что-то типа анемичного объектного подхода, не пытаясь тащить инфраструктуру какого то ECS подхода.
Для проблемы веревки и проблемы декомпозиции вообще есть на самом деле простое решение - правило владения.
Решать должен тот, кто знает про все свои детали.
Соответственно в примере с веревкой ни юнит не содержит веревку, ни веревка - юнит, соответственно они не должны решать, как им взаимодействовать.
Кто тогда должен решать - другой вопрос, на который этот принцип ответа не дает)
Херня написана - хорошую работу по промыванию мозгов проделали маркетологи юнитехов, которые рассказали, что ECS это про скорость и приравняли его к DOD (https://en.wikipedia.org/wiki/Data-oriented_design). Нет, ECS - это не про скорость, про скорость - это DOD. ECS не накладывает никаких требований и ограничений на то, как будут реализованы кишки, удобно ли для кеша разложены данные и будет ли оно максимально быстро обрабатываться - следование DOD является особенностью конкретной реализации. ECS - это архитектура, причем скорее архитектурный паттерн, не имеющей фиксированной реализации. Если бы оно было про скорость, то Entitas (https://github.com/sschmid/Entitas) никогда бы не появился на свет и не был бы до сих пор самым быстро растущим по популярности ECS-фреймворком (сейчас уже по 1к звезд в год) с 2015 года, ведь он весь на классах, через интерфейсы, на реактивных системах и местами постоянно аллоцирует память, про производительность вообще не стоит заводить разговор - это самая медленная реализация из всех существующих на сегодня.
Смысл ECS не в скорости, а в гибкости и простоте рефакторинга. Если системы распилены на независимые части (features, "фичи"), то их можно наращивать и выпиливать почти безболезненно, пользуясь понятием "composition over inheritance". Берут его именно по этой причине, когда ТЗ или не готово, или меняется каждую неделю - с ECS рефакторинг проходит менее болезненно, чем в красиво выстроенной абстракции ООП-типов.
Да, в ECS неприятно делать обработку любых иерархических данных типа графов, работы с UI и т.п, но не нужно все тащить в ECS, оно прекрасно живет рядом с ООП-сервисами, реализующими проблемные места.
Непонятно, почему после миллиона статей про ECS продолжают приравнивать ECS к DOD или, что еще хуже, к UECS/DOTS, хотя это всего лишь частный случай реализации.
Вы не правы в том, что производительность не ассоциирована с ECS.
Практически все ее упоминания или реализации на этом сосредоточены и так было с момента ее создания.
Cама концепция систем сосредоточена на пакетной обработке компонентов, иначе их бы можно было бы назвать командами и применять к отдельной паре компонентов.
Есть известная цитата про нарезку хлеба (с которой я не согласен).
Вторичная система индексации, когда у вас есть Entity и это просто индекс, так же направлена на это, иначе можно было бы просто использовать ссылку на объект entity.
Безусловно важным фактором является и разделение логики и данных - и, на самом деле, я критикую это не в последнюю очередь как способ создать реально сложные и плохо обслуживаемые решения, когда из-за позднего связывания порядка систем и очень сильной декомпозиции элементов просто тяжело понять, что происходит.
Остальные факторы могут быть достигнуты без ECS:
Composition over inheritance является хорошей практикой и в современном ООП сообществе, глубокие иерархии очень хрупкие.
По сути обычная среда Unity - это composition over inheritance, это, можно сказать, entity-component архитектура.Для достижения гибкости не нужна полная ECS, достаточно просто компонентов и Data-Driven дизайна, когда игровые сущности можно собирать из кусочков ориентируясь на данные.
Именно поэтому все современные движки это так или иначе дерево узлов и компоненты на них.Анемичный дизайн, когда логика и данные развязаны, тоже много где характерен и для него не требуется волшебства.
Хранимое состояние - опять же, для этого нужны какие то общие методы сериализации и десериализации объектов, а не вся архитектура.
Не в последнюю очередь моя статья про то, что разделение логики и данных кажется хорошей идеей, но возможно это только кажется.
ООП буквально придуман для того, чтобы собрать это вместе по хорошей причине - локальность данных и кода, защита целостного состояния объекта. Безусловно это может мешать, создавать хорошие абстракции непросто, но вы можете регулировать уровень этой локальности. Без этой абстракции создавать хорошие абстракции совершенно нереально.
Я бы не сказал, что сложные задачи, где нужны гибкие отношения многих ко многим сильно упрощаются в ecs
ООП буквально придуман для того, чтобы собрать это вместе по хорошей причине - локальность данных и кода, защита целостного состояния объекта. Безусловно это может мешать, создавать хорошие абстракции непросто, но вы можете регулировать уровень этой локальности. Без этой абстракции создавать хорошие абстракции совершенно нереально.
Я бы не сказал, что сложные задачи, где нужны гибкие отношения многих ко многим сильно упрощаются в ecs
Я много лет писал игры (как хобби) на ООП. И основная проблема всегда была в том что в какой-то момент добавлять фичи становится сложнее чем всё переписать. И компоненты юнити тоже не слишком помогают - каждый компонент со временем превращается во все более и более сложную штуку и любое серьезное изменение затронет почти все из них. Допускаю что да, я не умею в правильную архитектуру. Но как ни продумывай архитектуру заранее, все равно в какой-то момент она перестает соответствовать реальности игры и ее надо переделывать, а заниматься этим либо лень либо некогда.
А вот когда я попробовал ецс возвращаться к ооп нет никакого желания - больше никакого продумывания архитектур, просто декомпозируй компоненты и пиши фичи отдельными системами. Даже если нужны серьезные изменения, они будут локализованы в нескольких системах и что самое приятное - не надо задумываться к какому месту в иерархии правильно отнести этот код, вопросов типа "должен ли юнит знать о том что качается на веревке или это веревка должна знать о юните", просто добавляешь еще компонент и еще одну систему.
не надо задумываться к какому месту в иерархии правильно отнести этот код, вопросов типа "должен ли юнит знать о том что качается на веревке или это веревка должна знать о юните", просто добавляешь еще компонент и еще одну систему.
О, это прям классика, да
Про веревку это правда.
Но так же легко потом пули на веревках качаются, потому что забыл, что компонент, ответственный за это, переиспользуется там.
так это отдельный компонент - "качается на веревке". Да, можно его навесить на пулю или даже на постройку и они тоже будут качаться.
Для меня это скорее плюс, т.к. заранее не предугадать в какие дебри сочетания механик заведет фантазия геймдизайнера и ецс как будто специально на это рассчитан.
Да, есть и минус - нет типизации, т.е. можно случайно навесить компонент туда где его быть не должно. У меня был например такой баг - в платформере перестала работать статическая геометрия. Оказалось что я для отладки навесил на платформы компонент "можно подобрать" и забыл убрать. Игрок касался платформы, "подбирал" ее и падал сквозь нее. Но такие баги на мой взгляд - небольшая плата за удобство рефакторинга и расширения.
Поинт всей статьи в том, что про то, как объект качается на веревке, придется задумываться в любом случае.
Сказать, что ECS решит это за вас, безо всяких орг практик, дисциплины и организации - портал в маленький ад.
Только ад не такой, как переусложненное ООП, а другой, когда ты не можешь найти концов и краев и все пули застревают в веревках, потому что при пролете на самом деле качаются на них.
В ECS заметно сложнее наговнить. Это архитектура которая не трубует большого количества времени и не генерирует много техдолга при его нехватке. Запас прочности с этим напрямую связан, беря ECS и строя игру вокруг него ты вряд-ли "промажешь", то есть ты вряд-ли окажешься в этом самом аду.
Это опыт анекдотический, но недавно прийдя на проект, где каждый день десятки программистов пушат сотни коммитов, я не чувствую себя потеряным. Вот эта однородность и понимание где какой кусок логики/данных может находиться, а также простые и чётки правила парадигмы не дают качеству кода упасть ниже определенного уровня. Ну может есть какие-то легаси системы, но они как правило не очень большие, да и отдают только компоненты и сущности, и с этим уже можно работать.
Если взять данный проект, куда я попал, в текущем состоянии, всё продумать, то можно его написать на ООП, в теории лучше, чем это позволил бы ECS. Можно сделать классный нейминг и методы, которые грамотно всё инкапсулируют и делают работу удобной, но на "хорошее" ООП нужно времени. На ООП хорошо писать то, что хорошо изучено и где более менее понятные требования, и это не совсем про игры.
Вы не правы в том, что производительность не ассоциирована с ECS
Так я про то и написал, что одни понесли, а другие охотно поверили. Производительность абсолютно никак не связана с ECS, а связана с логикой обработки данных - скорость в итоге может быть как лучше, так и хуже.
Практически все ее упоминания или реализации на этом сосредоточены и так было с момента ее создания.
Абсолютно ничем не подтвержденное высказывание. ECS впервые как архитектурный паттерн появился в dungeon siege, а это 2002 год. Ни про какую скорость разговора не было, была попытка управлять взрывным ростом механик и поддерживать их в рабочем состоянии.
Следующая известная веха - это GDC 2015, когда авторы entitas начали активно продвигать этот паттерн и конкретно свою реализацию в рамках юнити. Ни слова про производительность не было ни тогда, ни на следующем GDC2016, где опять же было выступление про удобство декомпозиции, добавления и удаления игромеханик без ломания остального кода.
Юнитехи со своим "performance by default" заявились на ECS-сцене только в 2017 году и то не смогли ничего работающего показать раньше середины 2018, причем этим пользоваться было нельзя, а производительность была ужасна.
Безусловно важным фактором является и разделение логики и данных - и, на самом деле, я критикую это не в последнюю очередь как способ создать реально сложные и плохо обслуживаемые решения
Плохо обслуживаемые решения можно создать на чем-угодно и ECS тут никак не помогает и не мешает.
ООП буквально придуман для того, чтобы собрать это вместе по хорошей причине - локальность данных и кода
Внезапно, от локальности и когерентности данных в памяти/кеше и производительности по этой причине перешли к локальности данных по отношению к логике. В чем тогда был смысл рассказывать про производительность? Экземпляры ООП классов в общем случае всегда размазаны по памяти случайным образом и никогда не смогут догнать на тех же линейных переборах DOD-подход, когда данные лежат плотно и подряд (и нет, это опять сравнение не ECS с ООП, а DOD с ООП).
Я бы не сказал, что сложные задачи, где нужны гибкие отношения многих ко многим сильно упрощаются в ecs
Тут какая штука - с ецс ты просто садишься и пишешь код как получится, на ходу подправляя неудобные места, тебе просто не нужно иметь в голове какую-то стройную архитектуру, а только набор идей/правил по взаимодействию различных подсистем. ООП-шники этому не верят и скорее всего именно отсутствие строгой архитектуры их и пугает в ECS, что все настолько гибко, что может быть изменено в произвольном направлении и относительно без боли.
Хм, а можно вопрос, вы разрабатываете проекты один или в команде?
Моя проблема с ECS в том, что нельзя изменить все в произвольном направлении из-за когнитивной сложности - буквально крайне тяжело понять, как работает условная абстракция, если ее писал не ты.
То есть такая проблема везде есть, конечно же, просто в ецс с произвольным разделением чтобы понять поведение, условно, юнита, нужно в голове поднять целый граф объекта - все компоненты позиции, здоровья, статусы и флаги.
И несколько систем, обязательно в нужном порядке, потому что порядок, очевидно, критичен.
В итоге любой процесс (скажем, получение урона, вместе со всеми деталями - просчетом доп типов урона, смертью персонажа, анимацией попадания и прочего) размазано по десятку систем.
По факту компоненты флажки используются как переменные связывания вместо функций по порядку или событий.
В итоге на ровном месте ты получаешь аналог event-hell.
У меня есть стойкое ощущение, что люди живут с этим event-hell и такие "I'm fine", просто потому, что не знают, что есть методологии, как уменьшить это.
Но это ведь сложно - правильные архитектуры нужно делать.
В итоге на самом деле решения на ECS имеют архитектуру - это просто нотации и договоренности в команде, может документация, что за чем следует и какие окончания у компонентов, заведующих событиями. И так как инструментальных решений организовать это нет или мало, на самом деле это увеличивает требования к архитектуре.
Если же ты вываливаешься за пределы упорядоченных систем, например если нужны сложные связи или дерево - это как писать на сырых ссылках в C++, тебе нужно проверять каждый объект на наличие компонент и возможность обработки.
Про идеи организации можно почитать вот тут https://habr.com/ru/articles/742376/
Какие-то административные договоренности по взаимодействию нужны, да. Еще не стоит мельчить с компонентами, иначе это на самом деле может превратиться в неуправляемое месиво, когда никто не будет знать как и что должно работать. Функционал стоит делить на "фичи", когда есть блок компонентов, управляемых блоком систем, а снаружи к ним идет обращение через создание сущностей-событий или навешивание маркеров-событий, а дальше они сами работают. Когда логика разбивается на подобные логические блоки - управлять ей становится проще. Это все решается административными мерами - какими-то правилами, которыми должны руководствоваться все со-командники, т.к строгих правил не существует из-за гибкости самого ECS-подхода (одни правила подходят на одном проекте, другие на другом).
Вы правы, такая проблема практически с любым кодом присутствует. Но если в ООП/КОП разная логика намешана в одном месте, то в ECS у тебя конкретная система делает что-то конкретное и вкурить её куда проще. А вот вкурить весь пайплайн данных на сущности если проект большой - может быть невозможно, это правда.
Для больших проектов на ECS требуется грамотное проектирование, разделение на фичи и договорённостями с командой, как раз для того чтобы избегать описанных вами проблем, впрочем для больших проектов всегда это нужно вне зависимости от выбранной архитектуры :D
Искренне не понимаю почему было не использовать просто обычное дерево в виде класса внутри компонента. Хотя некоторые фреймворки ограничивают использование ссылочных типов.
Возможно биас вызван тем, что для ООП даже маленькие проекты изначально делаются с не очень качественной декомпозицией.
Ничего не мешает делать компонентную структуру на обычных unity компонентах, разделить их на маленькие части и комбинировать.
Но одна из важных мыслей моей статьи - ECS не решает эту проблему автоматически.
Так же и не приносит особых преимуществ на ранних стадиях - просто не используй ООП и пиши как попало, получишь ту же "все ко всем" декомпозицию
И да, Entitas очень сосредоточен на производительности - он использует массивы структур, сложную систему запросов для выбора систем обработки компонентов и кодогенерацию.
Мой основной опыт это Entitas и несколько самописных решений, Я не использовал Unity-ECS в коммерческих проектах.
Абсолютно нет, Entitas построен исключительно на классах, про структуры автор начал заговаривать в рамках разработки нового фреймворка с атомарными компонентами, где все разбивалось вплоть до отдельных значений, но это было в 2020 году и все благополучно умерло.
Я свои самописные поделия начал делать как раз в конце 2017 как альтернативу платному кодогену Entitas, который проблемно ставился на macos. В начале 2018 была написана реализация на классах, которая обогнала или показала такую же производительность как Entitias, но без кодогена - задача была выполнена и появился LeoECS Classic, про Entitas больше не вспоминал. В 2019 эта реализация переехала на структуры и скорость работы еще возросла - Entitas все это время был в коме и не развивался.
Хм, ваша правда, Я спутал entitas и Leo ECS
В LeoECS нет кодогенерации, ответственно заявляю как автор.
ОМГ, а что я тогда использовал?
Структуры и селекторы для классов были, но есть ощущение, что кодогенерация тоже была для гетеров.
Так опенсорс же, форкаешь и дописываешь то, что тебе нужно, а потом тебя форкают дальше и перепиливают под себя. Ограниченный кодоген в виде патча на ядро был в классике и то только для тех, кому 6 компонентов в фильтре было мало. Т.е кодоген по сути для исправлений в ядре, а не для пользовательского кода. Такое количество компонентов не совсем нормально и должно быть поводом задуматься о пересмотре компоновки данных, но механизм расширения был дан. В лайте уже не надо было патчить ядро и можно было собирать фильтры любой сложности на стороне клиента без изменений в ядре.
Нушож, время обеда, можно и прочитать...
Сейчас будет куча цитат и моих контр-аргументов.
TLDR: автор путает DOD и ECS, смешивает ECS как архитектурный паттерн и реализацию ECS фреймворков, ну и вцелом не совсем понимает что представляет собой ECS архитектура.
Одной из самых важных проблем, которые ECS призван решить, является производительность
Нет, не является. Одна из самых важных проблем, которую решает ECS, это гибкость архитектуры. Об этом я писал в своей статьей, но, судя по всему, автор её не читал.
производительность доступа к памяти
Этим занимается DOD, а не ECS
Теперь за выделением памяти следит ECS, она располагает все компоненты в чанки - массивы с заранее выделенной памятью и одним типов компонентов.
ECS про это ничего не говорит и не занимается этим, но вот ECS-фреймворк уже может устроить такую оптимизацию. Например, в тупую можно реализовать ECS так, чтобы у тебя сущность была классом, внутри которого лежат её компоненты(то есть без глобальной локальности памяти) в виде словаря type-object. И я даже встречал такие фреймворки...
И если вы не подумали про это на старте, реализация может оказаться весьма сложной, в то время как в ECS она есть из коробки.
Нету в ECS этого из коробки. В паре ECS фреймворков это есть, но лишь в паре.
но создаст большие сложности с обслуживанием кода
Может создать, а может и не создать. Как впрочем и любой другой паттерн, если его использовать неправильно.
Вам следует начать оптимизацию вашей игры с контроля этих величин, и никакой ECS вам не поможет.
Вот это правильный довод. Залог хорошей оптимизации - это профилирование и устранение узких мест. ECS тут совсем непричём, игровая логика занимает относительно небольшую часть CPU загрузки и если она тормозит, то скорее всего тормозит конкретный алгоритм.
Продолжение будет в комментарях к этому комменту, чтобы не засирать нижний уровень комментов...
Шутеры? - Симуляция сотни игроков и тысяч пуль для ECS это даже не разминка, с этим легко справится обычный код, вы можете даже не получить преимущества.
А если завтра прилетит геймдиз, который захочет чтобы "камера убивала"? В ООП иерархии это может оказаться неподдерживаемым и придётся много костылить, а в ECS накинул компонент, добавил нужную систему(если вообще нужно) и всё готово.
И мы даже не говорим про пиксельные инди рогалики и 3-в-ряд.
Знаю разработчиков, которые очень довольны тем, что выбрали ECS для разработки 3-в-ряд как раз по причине гибкости :)
Важно отметить, что обычное ООП тоже не прямо уж медленное.
Так никто этого и не утверждает вроде бы. Я даже больше скажу: невозможно сделать игру на ECS совсем без использования ООП(ну ладно-ладно, можно, но это такой гемор, особенно на Unity), поэтому нормальной практикой считается комбинирования ECS с ООП там, где оно нужно.
В то же время, ECS по сути сама занимается управлением памятью, и не факт, что во всех сценариях она делает это эффективнее.
Не занимается ECS памятью. В C#-ECS-фреймворках это по прежнему делает компилятор за редким исключением, где нужен был полный контроль над памятью(как раз для сериализации, например).
Резюмируя: в вашей игре, вероятно, тормозит не игровая логика, соответственно и оптимизировать нужно не ее.
С этим утверждением я солидарен
Многие пропагандируют ECS как решение по умолчанию, потому что “просто используйте ее и получите хорошую производительность за бесплатно”.
Так поступают только юнитехи и те, кто не пользуется ECS. ECS не сделает ваш проект супер-быстрым, но сделает вашу жизнь как разработчика игровой логики проще.
Порождение, передвижение, попадание - это теперь не разные функции в одном методе близко друг к другу, но 3 системы, где код организован не для вас, а для оптимальности прохождения массива.
Это не для оптимальности нужно, а для разделения ответственности. Одна система занимается тем, что спаунит объекты. Другая система занимается тем, что двигает объекты. А третья тем, что обрабатывает попадания(наносить урон будет скорее всего четвертая система). Классическая S из SOLID.
Эта архитектура навязывает вам чрезмерную декомпозицию и когнитивная сложность понимания такого кода очень высока.
Тут склонен согласится. Когнитивно с ECS работать сложнее чем с ООП. Но с другой стороны "чрезмерная декомпозиция" даёт ту самую гибкость и расширяемость архитектуры, которой славится ECS.
Хотя если подумать, то ECS и не заставляет делать "чрезмерную декомпозицию", вполне себе можно иметь жирные компоненты, где будут все данные для условной пули, но ты сам захочешь разбить этот жирный компонент на несколько маленьких, когда у тебя появятся разные виды пуль с разными свойствами.
может быть довольно сложно понять, где заканчивается юнит и начинается пулька
Потому что в ECS нужно думать не объектами, а поведениями и тогда всё станет проще
Во-вторых - у вас нет базовых примитивов. Хотите делегат? Их нет, используйте компонент. Полиморфизм? Нет, это enum и несколько систем. Фильтр по циклу? Вам нужен компонент + система. Нужно дерево? Деревьев нет, используйте компоненты со ссылками на сущности.
[...]
У вас нет половины современных инструментов программирования, только императивное программирование и базовые структуры. Либо, вы можете использовать все, что захотите - тогда у вас будет мутант, который не имеет преимуществ ECS.
Вот это самая большая ложь. Никто ничего не забирает у разработчика при разработке на ECS.
Хочешь делегат - засунь его в компонент и дёрни из системы.
Хочешь полиморфизм - разбей данные на разные компоненты и комбинируй вместо полиморфизма. Об этом есть в моей статье.
Хочешь дерево - напиши своё ООП-дерево и запихни его в компонент.
Самое главное в ECS - логика должна быть только в системах, а в компонентах только данные.
В ООП у вас есть приватные переменные и интерфейсы для сокрытия деталей
Тебе не нужно скрывать детали, когда у тебя каждая логика и так обособлена в своей системе
понятные паттерны организации кода
Ну так ECS сам по себе и есть паттерн организации кода :D
Я понимаю что хотел сказать автор, поэтому у меня есть контр-аргумент - для ECS уже тоже придуманы "понятные паттерны организации кода", как например в этой статье.
Конечно, классический код тоже можно сделать запутанным и с плохой декомпозицией, но для ECS его очень легко сделать таким
Это правда. С ECS очень легко можно всё запутать. Именно для этого мы и пишем статьи с советами по разработке с использованием ECS, чтобы люди знали как можно организовать свой код, чтобы не путаться.
Но вероятность ошибок, сложность понимания и расширения такого кода очень велики и быстро растут с ростом проекта.
Частично согласен, об этом сказал выше. С другой стороны весов больших проектов у нас жёсткая ригидность ООП иерархии, когда вносить изменения в неё становится очень больно(или практически невозможно), в то время как в ECS ты просто добавляешь новый компонент и новую систему(можно к ней Unit-тест написать сразу) зачастую не трогая старый код.
Но это всего лишь инструмент, необходимо использовать его правильно.
Всё так, ECS не серебрянная пуля, а инструмент со своими плюсами(и производительность далеко не главный из них) и недостатками.
могут требовать максимальной производительности игровой логики и взаимодействия большого количества игровых объектов
Для этого в контексте Unity есть Jobs + Burst, ECS тут совсем не нужен.
Жгите.
Жгу :)
Важно понимать, что вся игра не обязательно должна быть написана в этом стиле. Возможно, оправданным будет как раз обратный подход - вы точно выделяете то, к чему есть эти супер требования. Стейт игры, синхронизируемая по сети модель сессии боя. Остальной код игры, интерфейс, мета часть, могут быть написаны в обычном ООП стиле, с упором на удобство и понятность кода, либо удобство и понятность расширения, редактирования дизайнерами и прочими требованиями.
Я бы как раз порекомендовал наоборот: вся игровая логика на ECS с вкраплениями ООП в нужных местах(деревья, сеть, сохранения и тп).
Практически все ее преимущества могут быть использованы отдельно от нее.
По отдельности преимуществ ECS можно достичь, писать код для идеальной тестируемости/модульности, заморачиваться про SRP, но зачем лезть из кожи с ООП если можно просто разделить данные и логику?
Кстати, DOTS не требует ECS, его инструменты типа jobs можно использовать отдельно.
Так и есть, поэтому и не стоит смешивая конкретную реализацию Entities из пакета DOTS с ECS архитектурой как таковой.
Я кончил
Мне кажется, что "если просто разделить данные и логику" - вот это тоже не правда.
Это подается как простое решение, фигячь как хочешь, всегда понятно, что и где добавить.
Проблема в том, что это не решает архитектурных проблем в организационной части.
Архитектура это не только что у меня есть данные и код, архитектура конкретной игры - это конкретно ваши сущности, ваши пули, юниты и что там еще есть.
Если это организовано само по себе разделение на логику и данные никак не влияет на то, что пуля должна наносить ущерб.
Мы использовали ECS как раз для match 3 и когда речь зашла про возможное взаимодействие каждого с каждым ECS был организован так же сложно. Тут ООП подход ломается влегкую, Я согласен, но решение находится на организационной стороне, нужно придумать хороший список абстракций, возможно разделить процесс на триггер и эффект и тому подобное. Решение которое не зависит от деталей организации.
И когда ты к нему приходишь, все равно придётся переписывать.
Вместе с тем статьи по ECS описывают все так, как будто проблемы не существует, надо лишь избавиться от ООП и все станет легко и приятно.
Вместе с тем, данные с процессами вместе соединяют не просто так.
Есть несколько представлений, со стороны которых можно работать - со стороны состояния и со стороны процесса.
И штуки как корутины, асинки, колбеки и прочие реактивные библиотеки придуманы для того, чтобы держать близко контекст процесса - действие за действием, которые можно обозреть.
ECS представляет все как один шаг тысячи ног одновременно, что может привести к аду, когда ты пытаешься понять поведение сущности.
В теоретическом абстрактном мире системы могут быть написаны независимо, чтобы можно было понять что происходит только по компоненту и системам, использующим его.
На практике чтобы понять поведение условно юнита, нужно развернуть в голове целый граф из многих компонентов и систем в нужном порядке, понять важные и не важные части и только потом получить данные, чтобы внести изменения.
ООП не идеален, но буквально заточен на эту изоляцию. ECS концептуально ее отвергает.
Возможно вы правы и во многих статьях упор действительно делается прежде всего на композицию и решение архитектурных проблем.
Тем не менее преимущества производительности подчеркивались тоже с ранних пор и многочисленные реализации, включая Unity ECS или ecs на rust напирают на это.
Я встречал это многократно и про это же говорит типичная реализация, в которой entity - это идентификатор, а не объект, а системы предназначены для обработки данных батчами.
По сути без этого ECS можно сделать на обычной юнити, просто используя GO и компоненты с публичными полями.
Эти реализации тащат определенные правила - обычно для систем сущности выбираются неким специальным механизмом фильтров, вызывающим систему только на определенном наборе компонент / единичном компоненте.
А работа с ссылками на сущности в обязательном порядке обрастает экстра кодом проверки наличия компонента на этой сущности.
И то и другое вместе с овердекомпозицией серьезно запутывает код.
Но это действительно может быть важной частью моих проблем с ECS, хотя я критикую и организационную часть.
С таким определением в других фреймворках таких проблем может и нет.
Решились написать как-то простую демку, дабы проверить свои идеи о "тысячах юнитов на экране". После профилирования оказалось что UI занимает времени столько же, сколько рисование 50К юнитов и сервер для обработки их передвижения. Было грустно(
Так почему ECS вам может не подойти? Все просто - она вероятно не решит ВАШИХ проблем с производительностью, но создаст большие сложности с обслуживанием кода.
Это причина по которой может не подойти ООП. ЕЦС как раз в первую очередь решает проблему обслуживания кода, пилить и поддерживать проект на нём гораздо проще, даже прототип
Мой гет в том, что пилить и поддерживать на нем гораздо проще только прототип.
А дальше это становится кучей кода с компонентным аналогом event-hell, который очень тяжело понимать и обслуживать, потому что инструментов организации, помимо нейминга, практически нет.
Способы организации есть, вот в этих двух статьях расписаны :)
https://habr.com/ru/articles/665276/
https://habr.com/ru/articles/742376/
Я докопаюсь только до этой строчки, так как все остальное тут уже вроде как разложили по кирпичику.
> Эта архитектура навязывает вам чрезмерную декомпозицию и когнитивная сложность понимания такого кода очень высока.
Тут во-первых буквально просто заменить слово декомпозиция на абстракция и стрелочка поворачивается. Во-вторых а в классическом ооп нет проблем с декомпозицией? Ну и в третьих, при использовании ецс во многих случаях декомпозицию можно проводить по мере разработки, например, создать жирный объект который включает в себя все данные и жирные системы которые обрабатывают эти компоненты, и далее по мере необходимости разделять на отдельные части.
P.S. и если ECS это только про перформанс, то почему многие разрабы создают фреймворки для lua или js? Там кеш френдли в принципе не возможно.
Для тру ООП как его многие представляют чрезмерная архитектурная космонавтика еще более характерна.
И плохая декомпозиция.
Но ярых фанатов в геймдеве я видел мало.
Но ООП призывает начать с этого и признает проблему плохой декомпозиции. Собственно и ECS и многие паттерны для этого и нужны - потому что рефакторить больно.
Но ECS конечно же призывает к ультрадекомпозиции. Посмотрите на представленные статьи - они буквально говорят о том, что надеваем прыгательный компонент и у нас все прыгает.
Совершенно без контекста того, как самые разные объекты могут взаимодействовать с прыганием тоже треш получится
Открывая статью расчитвывал на более обширный список pros / cons, чем ходьба вокруг производительности.
В целом, всё что хотел сказать, уже в комментах было сказано, в защиту темы статьи, как критики ECS - у него, как и у любого подхода есть свои недостатки и "неудобные кейсы применения", можно и нужно было освящать именно их, акцентируя внимание на том, что это не серебрянная пуля.
Но строить статью на аргументе "оно не настолько быстро, как вам кажется" сомнительно, как по мне.
На самом деле основные проблемы, которые хотелось подчеркнуть, были именно организационными, а по поводу производительности мысли были лишь о том, что высокая производительность не стоит такой запутанной организации.
Но мне тут уже нормально так насыпали аргументов, что производительность вообще не важна, а организация на самом деле и есть основное преимущество.
Я с этим не согласен, но создать целую статью лишь с болью про организацию, особенно без хороших альтернатив (а сложные ООП проекты не будут так же содержать серебрянных пуль) я не готов.
Поэтому прошу прощения за неоправданные ожидания, в следующий раз постараюсь лучше.
В комментариях накидали много статей, в том числе разбирающих недостатки.
Поиск серебряной пули распространённая проблема у части программистского сообщества. Рано или поздно человек это перерастет, если развивается. Спасибо за статью, сам пишу в свободное время на Юнити, смотрел немного в сторону ECS пришел к тем же выводам. Для пошагового роглайта с изометрией в синглплеере ECS точно не пригодится.
Возможно, вам не нужен ECS