ПрограммированиеСтатьиОбщее

Отчет: Перенос увесистого инди Lua-проекта на Unity малой кровью

Внимание! Этот документ ещё не опубликован.

Автор:


Что-то непогодится в моих краях. Да и год прошел - можно подводить итоги.

Наверняка все видели амбициозный проект "Crossroad In The Void: Олдскульная партийная рпг", ведущийся эксцентричным, но пытливым разработчиком уже чуть более двух лет.

Раньше выглядел он так:

Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры

Предисловие
Что-то нужно менять
А какой есть выбор?
  JMonkeyEngine
  Urho3D
  UE
  Stride
  Unity
Развитие игры на новой платформе
Тулсет и свобода
Актуальный технологический стек
Послесловие

Предисловие

Чуть забегая вперед, раскрою прежний технологический стек проекта:
1. LÖVE (aka love2d). Это добротно сделанный фреймворк, написанный на C++ для написания 2D игр на Lua.
2. 3DreamEngine. Это расширение для LÖVE, целиком написанное сторонним разработчиком на Lua, превращающее LÖVE в простенький 3D-движок. т.е. рэйкастинг, загрузка моделей (OBJ), а также рендеринг, основанный на способности LÖVE выводить на экран многоугольники.
3. сторонняя библиотека для GUI написанная на Lua как расширение для LÖVE.
4. Ядро - много... нет, МНОГО луа скриптов, написанных автором. игромеханически игра находится в состоянии полнофункциональной альфы - по большому счету, фич можно уже не добавлять и только фиксить баги. Хотя что-то еще добавляется.
5. Визуальный контент. OBJ + текстуры. Любые эффекты - через код.
6. Общий контент. Карта статических объектов составляется в Tiled Map Editor, а вся динамика (положения и свойства NPC, ловушек, телепортов, сундуков, квесты, локализация) прописана в специальных декларативных Lua-файлах (похоже на JSON).

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

Как известно, Lua - язык довольно медленный. И даже LuaJIT (который как раз и входит в состав LÖVE) не способен спасти ситуацию, когда на луа начинается не расчет кол-ва урона, а рэйкастинг и рендеринг моделей, где буфер вершин представлен в памяти структурой вроде "shared_ptr<unordered_map<int, shared_ptr<unordered_map<string, float>>>>". Игра тормозила в самых неожиданных местах, при этом выглядя, мягко говоря, очень просто.

Но производительность - это только часть проблемы. Несмотря на нишевый жанр и очевидный долгострой, проект привлекает художников, а иногда и очень хороших. А художники любят делать картинку которая им нравится, пусть даже речи о High-end графике не идет. Описанный техстек во-первых накладывает дичайшие ограничения на сложность сцены, а во-вторых предлагает очень скудные возможности работы со светом, анимациями и эффектами. фактически художник может только предоставлять модели (без анимаций) и текстуры, а эффекты и свет просить кодить программиста, а то и самому в скрипте редактировать. В общем, художники страдают от таких тесных рамок выразительных средств.

Что-то нужно менять

Будучи старым поклонником трилогии рпг-шек Might & Magic VI-VIII (в свое время на пару с The Elder Scrolls раздвинувшими стандарты размеров игровых вселенных), с чешущимися руками раз за разом проходил мимо треда CITV. И раз за разом в личке общался с автором по техническим около игровым вопросам - как вообще живется и какие взгляды у автора на то "что хочется" и "что можется". И все больше понимал, что технология, применяемая автором сильно ограничивает рост проекта и лучше что-то поменять. Автор в свою очередь резонно предложения о смене техстека отметал - ведь он делает игру мечты, а не экспериментирует со стеком, тем более игра изначально типа-олдскул, а значит графические улучшения не в приоритете.

Прошлым летом я психанул и понял что на это смотреть больше нельзя. Проект нужно технически апгрейдить чтобы удержать/привлечь художников и дать на время забыть о тормозах. Но речи о переписывании игры на U* быть не может, т.к. никто этим заниматься не будет. С таким же успехом можно бы и просто свою РПГшку запилить с нуля, оставив автора этого проекта в покое.

Но есть решения и более ковровые. По сути, большая часть проблем в API 3DreamEngine, а его API довольно небольшой (используемая в проекте часть). LÖVE побольше, но тоже не такой уж большой(та часть, которая используется в Ядре ). надо просто заставить Ядро запускаться в ином окружении с минимальными изменениями скриптов. В окружении с более матерым движком вместо 3DreamEngine (но мимикрируя под его API).

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

А какой есть выбор?

JMonkeyEngine

Поясню, я не настоящий программист и моя вотчина - java (бэкенд для энтерпрайза). Так что всерьез рассматриваю и такие варианты (к тому же есть опыт в близком жанре, показывающий что ява в какой-то степени применима). Возможно многие удивятся, но при определенной сноровке java разгоняется до половины скорости крестов. И реализации интерпретатора Lua на java весьма быстрые по сравнению с C# аналогами (но луаджиту тоже сильно сливают). Тем не менее, JMonkey предлагает довольно скудный тулсет, и кроме возможного (но непростого в достижении) буста в производительности здесь ловить практически нечего.

Urho3D

Я не мог не рассмотреть какой-нибудь крестовый двиг, т.к. было интересно пощупать кресты обстоятельнее, а к тому же есть потенциальная опция срезать углы - оставить LÖVE для 2D и рендерить 3D другим движком, шаря окно/холст/хз_что. Отличная была идея, и суппортеры урхи (вернее RBFX) очень отзывчивые ребята, но через пару недель ковыряния в исходниках LÖVE, доках/туториалах по OpenGL и попытках найти/воспроизвести желаемый шаринг, у меня отклеился ус и началась аритмия. В другой раз...

UE

Ну тут понятно - high-end ассеты - это не олдскульно ни разу, кресты вызывают аритмию, а блупринты даже для java-программиста - как-то уж слишком.

Stride

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

Unity

Старался максимально убедиться, что вариантов больше нет, прежде чем начать работать в эту сторону, т.к. в успехе этого варианта я был практически уверен. C# для java-программиста как родной. Да и ну вы сами понимаете, художники в юньке могут сами эффекты делать и свет настроить.

Окей, выбрал Unity. MoonSharp (Lua интерпретатор на C#) очень тормознутый. Причем IL2CPP не помогает ничем - скорость такая же в рамках погрешности что и у Mono (это для тех, кто считает, что IL2CPP для скорости). NLua/KeraLua (готовые биндинги к нативному интерпретатору) несовместимы с LuaJIT т.е. тоже медленно, к тому же предоставляют слишком high-level обертки, что тоже обязательно сворует скорость и затруднит работу с документацией Lua API. Но очень быстро получилось заэмбеддить LuaJIT с помощью P/Invoke без единой строчки на C++. Вынес простые низкоуровневые биндинги в отдельную либу, кому интересно (поддерживает удобный просмотр скриптовых объектов при отладке C#) и поддерживаю по мере возникновения проблем.

+ Показать

Конечно, такой фокус добавил в работу с Unity краши с вылетом без вменяемого отчета (из-за глупых ошибок в работе с Lua-стеком), но это происходит достаточно редко чтобы держать сердечный ритм в норме.

Было решено полностью воспроизвести на шарпе средствами Unity весь нужный функционал как LÖVE, так и 3DreamEngine, т.к. подсунуть LÖVE в Unity - ну совсем не вариант, раз уж с открытым Urho3D не получилось. Как ни странно, хватило недели до того, чтобы получилось запустить игру уже под Unity с некоторыми ограничениями, незаметными на первый взгляд. Эти наработки намного убедительнее, чем советы "перепиши на юнити", так что дальше пошла уже командная работа.

Ранний вариант переноса:

Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры

Proof of Concept:

Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры

Развитие игры на новой платформе

Первое что было сделано после начальной стабилизации:

  • добавление поддержки анимаций - в скриптах при этом ничего практически не поменялось, конфигурация делается прямо в ассетах юнити.
  • перепады высоты. игромеханичести - игра все еще плоская (и такой и будет), но аккуратные перепады высот здорово разнообразят визуал без нарушения корректности игровых ситуаций. Все модели монстров и других объектов на стороне Unity выравниваются по ландшафту, стрелы выравниваются по прямой между стартом и финишем (по хинтам из скриптов).
  • делегация рэйкстинга Unity
  • теперь статический визуал настраивается в Unity в добавок к семантической статике в Tiled и динамике в скриптах.
  • замена двумерных эффектов красивым VFX и настройка их преимущественно руками художника. сделано через механизм оверрайдов - пути моделей в некоторой степени стали символическими, т.к. художник может на них повесить свои префабы, которые будут выданы скриптам вместо старых моделей.
  • Уже вскоре время благодаря усилиям художника в проекте стали появляться красивые тестовые ландшафты с анимированными деревьями, анимированные персонажи, костерки.

    Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры

    Тулсет и свобода

    Через три месяца уже стало понятно, что переход на такую гибридную платформу по рискам компенсируется пользой и можно дропнуть поддержку LÖVE. После чего удалось сильно оптимизировать некоторые аспекты, чуть-чуть переписав скрипты (просто не делая лишних переборов, которые в 3DreamEngine были логичными, а в Unity - лишними).

    Через примерно полгода уже назревал запрос в более-менее полноценном редакторе уровней на основе Unity. А именно - редактирование статики и расстановка точек для динамики. Процесс разработки тулсета затянулся из-за моего выгорания на работе, а также изначальной попытке оставить совместимость с Tiled. Но в итоге от Tiled полностью отказались в пользу Unity со своей обвязкой. Функционал поддерживается и развивается по мере его использования.
    Изображение

    Далее наконец дошли руки до моей старой хотелки. Напомню, что я поклонник именно M&M VI-VIII, а не M&M IV-V+X, т.е. вот эти повороты кратные только 90° и перемещение рывками по клеткам - это вообще не то. Но я знал что это не каприз автора, а попытка уменьшить производственные риски. Так что был реализован механизм, что вне боя партия может ходить в произвольном направлении на произвольное расстояние, как в обычных шутерах. По игровой модели, правда, партия все равно находится всегда в каких-то клетках, и в режиме боя на земле появляется сетка и партия мягко вгоняется в середину своей клетки. А вот пошаговый бой в режиме клеток (но со свободной камерой - в будущем) - это выглядит уже вполне. Да, у этого режима есть нюансы, но на мой взгляд недостатки (вгоняние в середину при начале боя и странности с некоторыми препятствиями) с лихвой заглушаются духом свободного исследования.

    (в отличие от видео, сейчас сетка видна только в бою, и она не так далеко простирается)

    Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры

    Актуальный технологический стек

    1. Unity
    2. Фреймворк на C#, являющийся средой для Lua-программы, частично имитирующий API LÖVE и 3DreamEngine, а частично предоставляющий скриптам новые функции.
    3. сторонняя библиотека для GUI написанная на Lua как расширение для LÖVE. она вполне работает на основе имитации API LÖVE.
    4. Ядро - те же луа скрипты, написанные автором. скрипты сначала переехали на новую платформу с ничтожными изменениями (пара if-ов в критичных местах), но затем уже стали появляться несовместимые изменения. хотя на фоне масштабов скриптов они все еще ничтожны.
    5. Визуальный контент. Полная свобода в настройке эффектов с минимальным вовлечением программистов. Современные форматы моделей, анимации.
    6. Общий контент. Мир редактируется прямо в Unity. Статику можно ставить любую, но держать в голове клеточную логику. Положения всех объектов (включая динамические триггеры) расставляются тоже прямо в Unity. Свойства проходимости редактируются тоже прямо в Unity. А вот игровые свойства объектов (содержимое сундуков, например) все еще в JSON-образных Lua-файлах. Это вопрос востребованности - появятся World-дизайнеры, желающие инструмент - сделаем инструмент.

    Послесловие

    Считаю реализацию перехода успешной. Условие "не мешать автору делать игру" выполнено. Проблема производительности испарилась. Нативных крашей не было уже очень давно (по крайней мере на Windows). Возможности художников значительно расширены, игра уже стала выглядеть лично для меня ощутимо приятнее. И конечно получил массу удовольствия от игры в настоящего программиста =D а теперь вот поддерживать все это добро... ;( шучу, это тоже интересный процесс - дел по платформе еще много.

    В проекте рады энтузиастам! Особенно World-дизайнерам (квесты, локации).

    #Lua, #RPG, #Unity

    24 июня 2022 (Обновление: 7 ноя 2022)

    Комментарии [18]