Русский
Русский
English
Статистика
Реклама

Ускоряем ваш Unity проект. ECS для MonoBehavior разработчиков

Магия вне Хогвартса

Привет, Хабр!

На обложке демо-игра Megacity. Она содержит 4,5 млн элементов Mesh Renderer, 5000 динамических транспортных средств, 200 000 уникальных строительных объектов и 100 000 уникальных аудиоисточников. Но самое удивительное, что вся эта мощь запустилась на Iphone X при 60 кадрах в секунду . Как все это возможно?

Пару лет назад компания Unity представила свой стекDOTS, на котором и построен проект Megacity. Это некий список технологий, которые в совокупности позволяют колдовать и ускорять ваш проект в десятки раз. В корне всей магии лежат 2 простых заклинания:

  • Если правильно управлять данными, процессору будет легче их обрабатывать, а если их легче будет обрабатывать, то игрокам будет легче жить.

  • Количество ядер процессора растет, но код среднестатистического программиста не использует все ядра процессора. А значит игрокам все же живется туго. На их устройствах можно жарить яичницу, а фреймрейт ведет себя как Джокер - непредсказуемо.

Для того, чтобы юным Unity волшебникам удалось осуществить вышеописанные постулаты, компания выпустила дополнительные пакеты:

Дары смерти от Unity Technologies
  • Job System - Пишите многопоточный код, даже если вы не знаете что такое "Race condition" или "Context switch".

  • Burst Compiler - Ускорьте код в 10 раз, просто добавив атрибут и отказавшись от ссылочных типов.

  • Unity Mathematics - Специальная математика, адаптированная под компилятор Burst.

  • Native Container - Обертка над неуправляемой памятью. Это такие же List, Array, Queue, но живут в мире без мусора. Мусор - это ваш код. Мусор - это то, что могут оставлять после себя мертвые ссылочные типы. Сборкой мусора в проекте занимается некий дворник - Garbage Collector, но он очень медленный и злой дядька . Да и Greenpeace советует убирать после себя трупы, не правда ли?

А сердцем DOTS является:

  • Entities - архитектурный паттерн Entity Component System (ECS), который ставит во главу угла данные, а не объекты, и тем самым переворачивает привычное представление о программировании среди ценителей ООП . Подобный подход развивает идею композиции над наследованием и позволяет легко адаптироваться под динамичные потребности гейм-дизайнера.

    ECS стоит рассматривать в первую очередь как архитектурное решение. Скорость - это бонус.

На текущий момент DOTS выглядит скорее проклятьем Unity Technologies, чем волшебной палочкой. Стек до сих пор не вышел в официальный релиз. И неизвестно когда Хогвартс распахнет свои двери для новых волшебников. Сейчас это крайне нестабильная штука, которую точно не стоит использовать в Production проекте.

Поэтому, давайте начнем колдовать вне Хогвартса.

Производительность! Бесплатно и без регистрации

Entity Component System - это сердце нового подхода от Unity. Но одновременно и самая нестабильная часть всего стека DOTS . Давайте попробуем применить эту технологию самим, без пакета от Unity Technologies.

Из чего состоит ECS?

Entity - это все, что вас окружает. Ваша кошка, сын маминой подруги, пицца - это все entity.

Component - это то, что делает ваш Entity особенным. У кошки есть хвост, у сына маминой подруги - мозги, у пиццы - кетчуп. Это все - компоненты.

System - логика, которая управляет всеми entity, у которых есть тот или иной набор компонентов. Хвост помогает всем кошкам балансировать в пространстве, мозги помогают всем сыновьям маминой подруги быть круче вас, а кетчуп позволяет любой пицце быть вкусной.

Если перенести аналогию на игровые объекты, то ваш персонаж в игре - это Entity. Компонент физики - Rigidbody, а система - это то, что будет управлять всей физикой на сцене, включая вашего персонажа в игре.

Согласно официальной статье , снижение количества Update функций и переход на чистый c# автоматически добавит скорости в вашу игру. А Job System, Burst Compiler можно применять к любой архитектуре. И если у команды Unity пакет Entities пока что официально не выпущен, давайте обратимся к кулинарным профессионалам из сообщества и посмотрим, как же они предлагают нам приготовить этот самым ECS.

Рецепт ECS под соусом Leo

Поиск Гугл по рецептам приводит нас к самому вкусному результату:

Leo ECS - очень легкий и быстрый ECS фреймворк, который не требует какого-то специфичного игрового движка. Он прост, быстр и не форсирует вашу интеграцию с Unity Engine.

Другие ECS рецепты, которые могут вас заинтересовать

Entitas - аппетитный фреймворк с самым большим комьюнити, но вся его проблема в том, что он работает на классах. Добавлять этот ингредиент сейчас не модно, повара предпочитают использовать структуры на компонентах. Классы почти в 2 раза медленней структур в синтетических тестах, т.к хранят в памяти ссылку. А данные тесты демонстрируют отставание по скорости готовки до 10 раз.

ECS.ME - потрясающий ECS фреймворк для Unity, приготовленный для сетевых игр с элементом отката (RollBack). Эдакий некоммерческий аналог Quantum от Exit Games. Рецепт очень-очень крутой и вкусный. Но чтобы rollback не дал трещину, нужно четко следовать правилам данного фреймворка.

EgoECS - ECS фреймворк с сильнейшей интеграцией в Unity. С его помощью можно готовить MonoBehavior в качестве компонентов. Если вам не важна скорость работы, EgoECS выглядит весьма хорошим рецептом. Каждая система - это всего 1 фильтр, кому-то такой подход может скручивать руки при написании кода.

Svelto ECS - очень амбициозный рецепт, с очень сложным API. Но я должен был его упомянуть. Скорее всего он не подходит новичкам, но если вы заинтересовались, то на habr существует перевод Wiki данного фреймворка.

Actors - изначально разрабатывался как набор утилит. В рецепте присутствуют реактивные переменные, которые могут нарушить порядок вызовов функций. Реактивщина в ECS может сбить вас с толку при поиске багов / ошибок в вашей игре.

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

Вот мы и определились. Чистый C# и соус Leo. Что может быть круче?

Превращаем GameObject в Entity

Если Leo ECS по умолчанию конвертирует игровые объекты из Unity Engine, то как интегрировать его с этим движком? Можно ли как-нибудь очень-очень легко превращать наши игровые объекты в Entity, чтобы процесс готовки был простым и понятным.

В этом нам поможет моя собственная библиотека UniLeo . Я написал ее для того, чтобы сохранить привычный flow работы с игровым движком Unity.

UniLeo автоматически конвертирует ваши игровые объекты в Entity и позволяет настраивать компоненты прямо из инспектора.

Перейдем наконец-то к коду

Подключаем пакеты через Unity Package Manager

Добавьте ссылку в Packages/manifest.json

"com.leopotam.ecs": "https://github.com/Leopotam/ecs.git","com.voody.UniLeo": "https://github.com/voody2506/UniLeo.git",

Или Unity Editor -> Window -> Package Manager

Компонент в Leo ECS - это обычная структура, но мы, благодаря UniLeo можем управлять ее содержимым в рамках редактора Unity.

Не забываем пространство имен
using Leopotam.Ecs;using Voody.UniLeo;
Создаем первый компонент
[Serializable] // <- Данный атрибут необходим, чтобы управлять компонентом из редактораpublic struct PlayerComponent {     public float health; }
Пример компонента с элементами Unity
[Serializable]public struct UnityExampleComponent {     public Rigidbody rigidBody;  public Transform transform public GameObject unityObject }

То есть, если в проекте нужно управлять физикой, необходимо создать компонент с переменной RigidBody. Таким образом можно управлять абсолютно любым элементом игрового движка Unity.

Теперь нам необходимо как-нибудь прикрепить наш компонент к игровому объекту, но как это сделать? Компоненты - это структуры. А движок Unity позволяет крепить к игровым объектам только классы, которые наследуется от MonoBehavior .

Но в UniLeo можно создать класс-проводник, который должен наследоваться MonoProvider и его можно крепить к игровым объектам.

Создаем класс-проводник
public sealed class PlayerComponentProvider : MonoProvider<PlayerComponent> { }

После того, как данный класс закреплен на игровом объекте, его можно предварительно настроить из редактора.

Отлично, теперь мы можем без лишних проблем настроить наш компонент прямо из редактора Unity.

Настало время написать первую систему. Для этого необходимо просто создать класс и реализовать один из готовых интерфейсов, чаще всего используются только:

IEcsInitSystem // Срабатывает 1 раз при инициализации

IEcsRunSystem // Срабтаывает на Update или Fixed Update метод

Пишем первую систему
class PlayerHealthSystem : IEcsInitSystem, IEcsRunSystem {    // Переменная _world автоматически инициализируется    EcsWorld _world = null;    // В фильтре просто описываем с каким компонентом     будет работать система     EcsFilter<PlayerComponent> _filter = null;    public void Init () {    // Сработает на старте    }    public void Run () {        foreach (var i in _filter) {            // entity которые содержат PlayerComponent.            ref var entity = ref _filter.GetEntity (i);             // Get1 вернет ссылку на "PlayerComponent".            ref var player = ref _filter.Get1 (i);            player.helth = player.helth - 10;         }    }}

Когда наша первая система создана, мы должны как-то запустить ее: для этого создадим стартап код ECS, это простой класс, который наследуется от MonoBehavior .

Запускаем ECS
class Startup : MonoBehaviour {    EcsWorld _world;    EcsSystems _systems;    void Start () {        // create ecs environment.        _world = new EcsWorld ();        _systems = new EcsSystems (_world)            .ConvertScene() // Этот метод сконвертирует GO в Entity            .Add (new PlayerComponent ());        _systems.Init ();    }        void Update () {        // process all dependent systems.        _systems.Run ();    }    void OnDestroy () {        // destroy systems logical group.        _systems.Destroy ();        // destroy world.        _world.Destroy ();    }}

Обратите внимания, что к вашему игровому объекты автоматически добавится компонент Convert To Entity , который позволяет выбрать предпочтительный метод конвертации ваших игровых объектов.

Выбираем метод конвертации

Convert And Inject - Создаст entity на основе компонентов, повешанных на игровой объект.

Convert And Destroy - После превращения GO в Entity , объект автоматически удалится. Может быть полезно, когда необходимо просто добавить определенные компоненты в ECS мир..

После запуска игровой объект автоматически сконвертируется в Entity. Система начнет отрабатывать свои методы. Мы успешно интегрировали Leo ECS в наш проект. Поздравляю!

Наверное у вас еще остались вопросы, я попробую ответить на них.

Вопрос-Ответ

Как работать с Prefab?

Вы можете порождать prefab любым известным вам способом, конвертация пройдет автоматически.

GameObject.Instantiate(gameObject, position, rotation, _world);PhotonNetwork.Instantiate <- рабоатет и в сторонних библиотеках
Как работать с ивентами в ECS?

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

// MonoBehavior void OnCollisionEnter(Collision collision){// Создаем новый entity и добавляем компонент    // Переменная _world хранится в Startup классе    EcsEntity entity = _world.NewEntity ();     var event = new EventComponent ();entity.Replace (event);    // Теперь просто можно перехватить этот ивент в любой системе}

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

Очень часто ивент-компоненты нужно очищать в конце кадра, для этого в LeoECS есть готовый механизм.

void Start () {    var world = new EcsWorld ();    _update = new EcsSystems (world);    _update        .Add (new CalculateSystem ())        .Add (new UpdateSystem ())        .OneFrame<EventComponent> () // Этот компонент удалится          самостоятельно в этот момент времени        .Init ();}
А что насчет многопоточности?

У Leo ECS есть готовая интеграция , которая позволяет запускать системы в разных потоках. Она не использует Job System и Burst Compiler , а использует стандартную библиотеку System.Threading.

Но вы вполне можете использовать и пакеты от компании Unity, они дадут намного больше производительности, но интеграция с ними не так легка.

На хабре уже существует отличный пост про Job систему. Вам необходимо вызвать ее внутри ваших Run методов в LeoECS.

Я пишу сетевую игру, как мне работать с ECS

Готовой интеграции для LeoECS с популярными сетевыми библиотеками на данный момент не существует, но передача данных осуществляется через ивенты, а как работать с ивентами я уже отвечал.

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

P.S

Да, возможно сторонние ECS решения не такие быстрые, как подход DOTS, но они позволяют существенно увеличить производительность относительно классического MonoBehavior подхода. Теперь вы знаете с чего начать свой Megacity проект!

Спасибо, что дочитали до конца!

Источник: habr.com
К списку статей
Опубликовано: 08.05.2021 16:18:41
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Программирование

Разработка игр

Unity

Ecs

Dots

Entity component system

Leoecs

Unileo

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru