У Unity всё плохо. Почему юнити говно

Однако, инструмент визуального программирования — blueprints — действительно очень мощный хотя и требует мануалов или знания названий 100500 встроенных функций.

Не Unity единым, или Как мы в Playrix разрабатывали свой движок

Во времена обилия и доступности качественных игровых движков вроде Unity и Unreal необходимость в разработке собственных возникает редко. Об одном из исключений хочу рассказать в этой статье. Речь пойдет об игровом движке компании Playrix, в которой я работаю почти 5 лет. Расскажу о его прошлом и настоящем, текущей функциональности, о том, к каким техническим решениям мы пришли и почему не стали использовать Unity.

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

Для начала давайте познакомимся. Меня зовут Виталий, я программист визуальных эффектов в Playrix. В компанию пришел почти пять лет назад, в конце 2015 года. Начинал с портирования проекта Gardenscapes на Mac-платформу, а затем перешел на проект Fishdom, где целиком погрузился в работу с графикой, анимацией и программными эффектами.

Придя в компанию, обнаружил, что на всех проектах используется единый игровой движок собственного производства. Он имеет длинную историю и как отдельный проект начал свое существование в 2009 году из общей части игры Brickshooter Egypt. На момент написания статьи движку уже 11 лет! Можно сказать, он самый старый из работающих проектов Playrix.

Итак, немного о функционале: первоначально движок поддерживал только платформу Windows, а спустя несколько лет появилась поддержка мобильных платформ. Он покрывал весь базовый набор потребностей и был хорошо заточен под наши проекты. Что мы имели тогда:

  • вывод графики;
  • взаимодействие с SDK;
  • работа с ОС;
  • работа с ресурсами;
  • работа с сетью.

Для комфортной работы не хватало только удобных редакторов и систем для организации игровых объектов. В старые времена у нас разные проекты работали с визуалом по-разному. Например, Gardenscapes применял систему окон, сделанную на Flash, что позволяло дизайнеру настраивать верстку и анимации. На Fishdom все было немного сложнее: отрисовка многих графических объектов велась напрямую из кода, что давало свои плюсы при создании визуальных эффектов. Но было ясно одно: нам нужна единая удобная система по работе с контентом игр.

Несколько раз поднимался вопрос использования Unity, но для этого понадобилось бы перевести уже существующие проекты с C++ на Unity. Этот процесс требует много времени и ресурсов. Избежать его не представлялось возможным, так как мы часто используем наработки одних проектов в других. Разные технологии сильно затруднили бы процесс.

В этой ситуации логичным решением стало развитие собственного инструмента — Visual Scene Object (VSO). В первой версии VSO еще не было ни кодогенерации, ни разнообразия редакторов. Он был написан за два месяца в связке с игровым проектом и стал основой дальнейшего развития. Опираясь на четкое понимание потенциала и востребованности продукта, команда из 4 человек активно работала над проектом, пусть это и не всегда совпадало с основным вектором разработки движка.

Дальше разработка шла эволюционно и постепенно, с учетом интересов и пожеланий проектов. Сейчас в команде VSO больше 10 человек, а времени на выход новых версий уходит намного больше, чем раньше. Помимо основной команды, в развитии VSO участвуют программисты других проектов. Когда Fishdom начал свой переход на VSO, я быстро включился в процесс написания новых behaviour-сценариев для упрощения процесса разработки. Часть этих наработок перекочевала в общую VSO-библиотеку.

Что мы имеем сейчас

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

Мы используем наборы объектов, собранных в сцены. Они состоят из узлов, которые, в свою очередь, состоят из ряда сущностей:

  • Transform — трансформация узла (позиция, поворот, масштаб).
  • Component — элемент отрисовки (не более одного, но может и отсутствовать). Это любой объект с возможностью отображения, например sprite или particle.
  • Behaviour — элемент, описывающий поведение и любую логику, их количество не ограничено.
  • Sorting — элемент управления порядком отрисовки узлов. Помимо регулирования порядка между объектами VSO, этот элемент помогает легко интегрироваться в запущенные проекты и обеспечить связь старых сущностей с новыми. С его помощью управлять порядком отображения может внешний код.

Программисты могут делать свои собственные component, behaviour, sorting. Более универсальные создает команда VSO, а узконаправленные — программисты внутри игровых проектов. Порой функционал из проекта переходит внутрь общего функционала VSO и становится частью библиотеки. Для написания своей версии класса требуется создать наследника от нужной базовой реализации и переопределить события (например, OnInit, OnClone). Вместо использования макросов, как это сделано в UnrealEngine, мы используем теги в комментариях.

READ  Лучшие копья в Assassin’s Creed Valhalla и как их получить. Как получить обруч беовульфа в викингах

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

Генерацию и сериализацию редакторов используют не только для визуальных объектов, но и для любых других классов, наследуемых от Serializable. Нужно только пометить свойства тегами. Ну а если наследовать свой класс от класса Asset, получим полноценный ассет, похожий по функционалу на ScriptableObject в Unity. Такая модель библиотеки ускоряет разработку новой функциональности и делегирует часть задач профильным специалистам.

UE4 отлично подходит для быстрого прототипирования, больших игр, у него открытый код, но для работы требуются знания в области C++. Большое преимущество – возможность создать полноценную игру практически без кода.

Теория

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

Entities представляет из себя реализацию популярного в игровой индустрии паттерна ECS. ECS это паттерн, где код делится на сущности к которым добавляются компоненты с данными, состоянием компонентов у сущностей управляют системы, которые эффективно перебирают сущности с нужными им компонентами и изменяют данные компонентов по надобности.

К примеру, у вас игра — шутер, в которой снаряд это сущность с компонентом Bullet в котором хранятся данные о расположении снаряда. Есть система движения снарядов, которая перебирает все сущности с компонентом Bullet и двигает их вперед, а есть система рендера снарядов, которая перебирает все сущности со снарядом Bullet и рендерит их.

Реализаций ECS есть великое множество, но в основном, используют следующие способы оптимизации перебора сущностей:

Хранение компонентов эффективно в памяти в соответствии с архетипом существа к которому они привязаны. Архетип это уникальное сочетание компонентов у существа. В случае Unity, компоненты хранятся в чанках по 16кб в соответствии с архетипом. Выходит, что чанки с компонентами хранятся друг за другом в памяти.

Распараллеливание обработки существ системой. Тут всё очевидно, двигать 50 тысяч снарядов в каком-то шутере быстрее в 32х потоках одновременно. От программиста не требуется особых телодвижений для управления многопоточностью, потенциально ECS может эффективно управлять потоками самостоятельно. В Unity роль управления потоками делегирована фреймворку Jobs.

Такой паттерн хорошо подходит сложным играм, в которых есть очень много сущностей которые надо очень часто перебирать (к примеру ММО). Вдобавок, ECS управляет зависимостями, позволяя игре становиться все больше и больше без последствий.Но есть и обратная сторона медали, ECS плохо подходит играм, в которых мало сущностей и их не надо часто перебирать (например 99% мобильного рынка).

Jobs это реализация безопасной мультипоточности путем создания экземпляра «работы». Работу можно запланировать, получить ее обработчик и выполнить ее. Также работу можно запланировать после другой работы, или вместе с другими работами. Таким образом создаются целые цепи последовательных задач. Сами задачи выполняются сразу в нескольких потоках. Например, вам надо умножить все числа массива А с вместительностью в 100 элементов и положить их в массив B. Это можно сделать в десяти потоках, в каждом из них задача будет обрабатывать по 10 элементов.

Burst это компилятор, который транслирует IL байткод в оптимизированный нативный код с помощью LLVM. В основном, используется для компиляции работ с Jobs.

Имплементация

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

Начнем с того, как же команда Unity хочет сделать C# таким же быстрым, как C++, а именно:

Создали новый компилятор для Работ с векторизацией и intrinsics (разве что без блекджека).

Создали нессылочные альтернативы массиву, списку, очереди и т.д которые дружат с Burst’ом. Особенность в том, что эти контейнеры надо аллоцировать и после их жизненного цикла освобождать, иначе утечка. Причем, аллоцировать надо не абы как, а с правильными лейблами (Persistent/Temp/TempJob).

Ввели в использование указатели на списки и указатели на функции. Также вам может понадобиться использовать Malloc, MemMove, MemCpy и подобные brand-new функции.

Я думаю, вы уже поняли к чему я клоню. Они решили, что лучший способ сделать сишарп таким же быстрым как и плюсы, это сделать из сишарпа плюсы! *занавес, бурные овации, публика в шоке*

Ладно указатели, ладно Dispose у контейнеров, но когда вы начали писать новый компилятор для языка, можно же было что-то заподозрить! Пытаться уже третий год реализовать стек технологий на языке, который не подходит вашему стеку, и при этом переделывать* язык, это же сумасшествие!

Ещё один пример несовместимости DOTS и C# это Jobs с Работой IJobChunk и производными. Для того, чтобы проитерировать 3 компонента c помощью IJobChunk, вам надо 43 строки кода. Ситуацию могли бы спасти макросы, но они в C# предательски отсутствуют!

READ  Сколько времени нужно, чтобы пройти Assassin’s Creed 2. За сколько проходится assassins creed 2

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

Звук. Версия пакета для звука 0.1.0-preview17 и за 3 года он так и не обновлялся.

Интерфейс. Тут всё проще, пакета для интерфейса с поддержкой Entities просто нет.

2д. Существует com.unity.2d.entities, но он создан для Project Tiny и работает в общем-то только с ним, о Project Tiny тоже позже.

Анимации. Пакет тоже существует, версия 0.9.0-preview.6, в теории использование возможно, на практике не очень.

Всё элементы движка, которые не требуют очевидного отдельного пакета. Свет, камера, партиклы и т.д, всеми ими нельзя управлять через Entities, что угодно делайте. Можете создавать псевдо-сущность с компонентом, к примеру, камеры, и отдельной системой в главном потоке синхронизировать поля между MonoBehaviour камерой и вашей псевдо-камерой, можете другие костыли городить. За 3 года решения от Unity так и нет.

*под переделыванием языка я подразумеваю минимизирование использования ссылочных объектов и, как следствие, кучи путем создания кастомных аллокаторов, компиляторов которые не поддерживают кучу и т.п.

Редактор событий и квестов — предназначен для создания различных туториалов, квестов и других событий. Может использоваться практически без участия программистов.

Простота и интуитивность

Еще одно важное преимущество Unreal Engine 4 – большая интуитивность. Если вы хотите сделать что-то с игрой в программе Epic Games, у вас всегда под рукой есть масса хороших решений, работающих всесторонне по умолчанию. Не нужно беспокоиться о каких-либо дополнительных вещах, которые необходимо загружать или переписывать вручную, чтобы заставить работать. В Unity придётся покопаться в правильных инструментах для создания того же, что в Unreal есть изначально. Где-то потребуется больше работы по программированию, а значит времени и средств.

Не секрет, что большая часть денег на реализацию игры оценивается в количестве рабочих часов хорошего программиста. Поэтому, если у нас ограниченный бюджет (а он обычно ограниченный), хочется сделать как можно больше, не вовлекая дорогостоящего специалиста во все мелочи. В Unity нет такой же массы полезных опций, поэтому подготовка прототипа игровой сцены дизайнером иногда ограничивается тем фактом, что у нас нет нужных вещей, и необходимо ждать, пока кто-то их напишет. В Unreal Engine 4 нужно изучить небольшие правила визуального написания сценариев, и можно делать практически всё.

В качестве примера возьмем две простые вещи: анимацию дверей и поставочную сцену. Чтобы сделать интерактивную анимацию открытия двери в Unity, нужно знать, как правильно запрограммировать такую механику на C#, подключить обнаружение столкновений и подготовить последовательность анимации – это три разных окна и требование знания языка программирования. Также возможна реализация и через инструмент визуального программирования Bolt – летом 2020 года он стал бесплатным.

В Unreal Engine 4 всё, что нужно сделать – создать соответствующий Blueprint (элемент визуального скриптинга), в который можно сразу добавить столкновение, последовательность анимации и подготовить рабочий механизм с помощью нескольких простых подключений. Процесс на двух движках во многом схож.

Второй пример – ролики, относящиеся к игровому процессу. В Unity вы должны ознакомиться с инструментом Cinemachine (предпочтительно в связке с Timeline) – на освоение уйдёт день-два. В UE4 всё, что нужно сделать – открыть инструмент Cinematic, вручную настроить камеру, одним щелчком отделить кат-сцену от остальной части игры, начать запись и простым щелчком сохранить то, что было создано в игровой мир. Буквально за 5 минут (возможно, немного дольше) можно показать раскачивающийся мост, растущие деревья или движущиеся объекты и использовать их в игровом процессе.

Поддержка и удобство

Когда мы создаем что-то в Unreal Engine 4, нужно просто выбрать одну конкретную версию, например, 4.26, и больше не стоит беспокоиться о том, что она будет обновляться каждую неделю и быстро устареет. Когда UE4 получает патч в одной редакции, переход практически незаметен.

В случае с Unity нужно подумать о том, в какой версией мы хотим работать, потому что не каждая получит долгосрочную поддержку от компании. Если это произойдет, патчей будет дюжина, и переход, например, с Unity 2020.1.2 на Unity 2020.1.12 связан с техническими проблемами.

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

С Unity всё немного сложнее, и иногда быстрее найти решение через сообщество, чем от самой компании. Кроме того, документация и учебные пособия по Unity могут быть сложными и нечитаемыми, в то время как Epic Games даже финансирует компании, которые создают хорошие учебники для сообщества Unreal Engine.

После приведённых сравнений может показаться, что начинать делать игры лучше в Unreal, но это не так.

UnrealEngine. Больше мне советовать нечего, скорее всего он вам подойдет. Писать код на C++ это сжигание тонны времени, но блюпринты могут вас спасти.

Ошибка № 4: игнорирование потерь производительности

Какими бы продвинутыми ни были современные устройства, всегда помните о производительности. Это качество грамотно выделит ваш проект среди конкурентов.

READ  Как победить Маргита Ужасное Знамение в Elden Ring. Гайд по битве с боссом. Как убить жермена

Есть много вещей, которые можно оптимизировать:

  • Вместо обновления используйте кеширование. Типичный пример – доступ к компонентам в сцене или интенсивные вычисления в скриптах. Кешируйте все при помощи метода Awake() или измените архитектуру, чтобы запускать эти вещи если они необходимы.
  • Используйте методы отсечения окклюзии ( occlusion culling – функция, отключающая рендеринг объектов, которые в данные момент не видит камера) или LOD ( Level of Detail – скрипт уровня детализации), чтобы ограничить визуализируемые части сцены. Используйте оптимизированные модели.
  • Попробуйте уменьшить количество вызовов отрисовки ( draw calls ). Используйте статическую пакетную обработку для неподвижных объектов и динамическую пакетную обработку – для движущихся. Однако вы должны сначала подготовить сцены и модели (пакетные объекты должны использовать одни и те же материалы), а пакетирование динамических объектов работает только для моделей с низким разрешением. Необходимо использовать более высокое разрешение текстур световых карт сцены (не сгенерированное разрешение, а разрешение вывода текстуры), чтобы уменьшить их количество, когда вы делаете свет в более крупных средах.
  • Не используйте прозрачные текстуры, когда в этом нет необходимости, так как это вызовет проблемы со скоростью их заполнения. Их можно использовать для сложной и удаленной геометрии, например, для деревьев или кустов.
  • Оптимизируйте шейдеры для повышения производительности. Уменьшите количество проходов, используйте переменные с меньшей точностью, замените сложные математические вычисления предварительно созданными текстурами поиска. Всегда применяйте профилировщик для определения узких мест, а также пользуйтесь инструментом отладки Frame Debugger.

Ошибка № 5: игнорирование проблем со сборкой мусора

Хотя Garbage Collector (сборщик мусора) – довольно полезная штука, есть несколько вещей которые, нужно четко усвоить. Следует избегать ненужного выделения памяти, чтобы сборщик мусора не запускался слишком часто и не снижал производительность из-за скачков частоты кадров. Все это определяется архитектурой приложения, но есть несколько правил, которым нужно следовать:

  1. Избегайте лишних затрат на обновления.
  2. Используйте простые структуры.
  3. Попробуйте предварительно выделить массивы, списки или другие коллекции объектов вместо того, чтобы создавать их внутри циклов обновления.
  4. Избегайте моно-проблемных вещей (например, выражений LINQ или циклов foreach), потому что Unity использует старую версию Mono ( платформы разработки с открытым исходным кодом, основанную на .NET) .
  5. Если необходимо обновление свойства строки в цикле, используйте объект StringBuilder.
  6. Используйте профилировщик для выявления потенциальных проблем.

Библиотеки с кодогенерацией, как FlatBuffers и Protobuf, подразумевают рукописные структуры, а сгенерированные структуры невозможно интегрировать в пользовательский код. Результатом использования этих библиотек было бы увеличение в два раза классов исключительно для сериализации.

Преимущества и недостатки

Движок обладает рядом положительных и отрицательных сторон.

К положительным относят:

  • Функциональный графический редактор – предусматривает создание локаций, моделей, расстановку объектов сцены с функцией тестирования результатов в реальном времени.
  • Кроссплатформенная среда разработки позволяет адаптировать проект для любой платформы путём внесения минимальных изменений. Минимизирует стоимость проекта.
  • Интегрированная среда разработки – программный комплекс для работы с движком, имея базовые знаниями программирования.
  • Поддержка плагинов – возможность установки компонентов, расширяющих возможности, повышающих удобство, скорость работы со средой.
  • Модульность – позволяет конструировать пакеты компонентов в одной игровой сцене.
  • Продвинутая методика создания объектов: вместо наследования путём размещения в древе они объединяются в функциональные блоки, что упрощает этап прототипирования.
  • Использование высокоуровневого языка C# с рядом готовых решений упрощает подключение программистов к разработке.
  • Качество поддержки – Unity сайт содержит описание всех функций движка, примеры их применения с пояснениями. Служба поддержки оперативно отвечает на вопросы.
  • Бесплатная эксплуатация для применения в личных и образовательных целях.
  • Сообщество – продвинутые пользователи всегда подскажут, помогут советом. На тематических форумах и блогах полно информации по Unity.

Недостатки платформы:

  • Проблемы при разработке многокомпонентных проектов из-за ограничений визуального редактора.
  • Сложности в подключении внешних плагинов – из-за отсутствия ссылок на них в программе модули придётся искать, устанавливать и настраивать самому.
  • Проблематичное внесение изменений в шаблоны экземпляров.
  • WebGL-редакция отличается рядом проблем с быстродействием, работоспособностью и стабильностью.
  • Стоимость – Pro-версия стоит $1800, а Enterprise — $4000 – неподъёмная сумма для фрилансера, их группы, небольшой студии разработчиков.
  • Быстродействие, по сравнению с другими движками, при разрастании проекта.
  • Большой размер скомпилированного файла особенно для мобильных платформ.

Игры на Unity

На движке выпущены сотни мобильных, консольных, десктопных развлечений, игр с дополненной реальностью. Он применяется в архитектуре, строительстве, производстве (многими автогигантами, такими как Audi, BMW, Lexus, Volvo), при создании мультипликационных фильмов.

Игровой движок Unity: почему его выбирают

Игра с дополненной реальностью

С компьютерных игр отметим:

  • Cuphead – платформер в стиле экшена с мультяшной графикой.
  • Pillars Of Eternity – кроссплатформенная «ролевка».
  • My Friend Pedro – платформер с возможностью управления временем.
  • Rust – симулятор выживания.
  • Subnautica – симулятор выживания в море.
  • Valorant – многопользовательский шутер.
  • Death Carnival – динамичный шутер.
  • Escape from Tarkov – отечественная многопользовательская стрелялка с элементами RPG.

Мобильные развлечения на Unity: Age of Magic, Chaos Lords, Jurassic Monster World, Royal Blood, Guns of Boom, Pokemon Unite и Go.

Мультфильмы, созданные с помощью Unity: Dead Pixels​​​​​​​, Bonfire, Jigsaw.

Оцените статью