Визуальные новеллы: спортивная разработка велосипедов
Создание визуальной новеллы – это не так просто, как кажется. Прототип на два диалога можно собрать на коленке, используя какие-нибудь инструменты. Но как только проект обрастает командой, а то и механиками на стыке жанров – каких-нибудь инструментов становится недостаточно. Но я пошел в этом рассуждении дальше: 4 года назад я подумал, что всех существующих на тот момент инструментов будет мало.
ВМЕСТО ПРЕДИСЛОВИЯ

Привет, Олимпийский! Я Тимофей Хаханов, и за последние годы я запрограммировал несколько визуальных новелл. Две из них – For the People и With Good Intentions, дошли до релиза, как и техническая демка True Magician.

Будучи техническим директором, а на части проектов еще и продюсером, я не просто выполнял таски – за этими проектами кроется техническая стратегия, и про нее сегодня пойдет речь.
Я расскажу, как Tool Engineering решает уйму ваших проблем. Разумеется, добавляя новых.

Дисклеймер 1
Эта статья про подход, а не про тонкости реализации. Технические детали – как-нибудь в другой раз.

Дисклеймер 2
В 2022 я покинул Brezg Studio, об играх которой в основном пойдет речь, и больше не имею отношения к ее деятельности.

Поехали!

FOR THE PEOPLE
Однажды мои знакомые позвали меня посмотреть билд проекта, который они делали: его нужно было немного починить, чтобы через три-четыре месяца вывести в релиз.

Разумеется, For the People вышла через полтора года: больше, амбициознее, и на другом движке.

ПРИКЛЮЧЕНИЕ НА 10 МИНУТ

Проект, который я получил, был собран на Unity, а для хранения сценариев там использовалась система визуального скриптинга сценариев Fungus. С ним, помимо критических багов, было две принципиальных проблемы:

  • Сценарий состоял из визуальных скриптов настолько запутанных, что никто в них не ориентировался.

  • Fungus, использовавший для скриптинга обвязку над lua, хранил скрипты в нечитаемом для системы контроля версий формате.
Система контроля версий, например git – это такая штука, которая трекает изменения в коде.

Она не просто хранит версии, но наглядно подсвечивает, чем новая версия отличается от старой.
Загвоздка в том, что эта подсветка работает, если данные хранятся как текст. Статьи и программный код так и хранятся, а вот Fungus хранил данные иначе.

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

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

Сюжетные скрипты – это тоже код. И чтобы работать с кодом эффективно и большой командой, нужны соответствующие инструменты. Которые уже есть, однако Fungus с ними дружить не хотел.

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

Поэтому я начал искать техническое решение, подходящий инструментарий. Это значило, что от Fungus надо избавляться, и переходить на сценарные системы, хранящие данные как код.

Где-то в этот момент я начал задумываться, что если и делать визуальное программирование сценариев, то как-то иначе...
Я перепробовал несколько решений, начиная от очевидных, вроде специального скриптового языка Ink, и заканчивая эзотерическими.

Самым запоминающимся, пусть и неудачным, был "Чиновник 1986" – прототип, использовавший IronPython, который мог играть сценарий как в Unity, так и буквально в системную консоль.

Old text-quest style.
Несколько экспериментов, пара презентаций команде, и решение было выбрано – переезд на Renpy.
RENPY

Хорошо...

Renpy – движок с открытым исходным кодом на Python. На момент разработки For the People – на Python 2, но недавно они наконец перешли на Python 3.

У Renpy есть два конкурентных преимущества:
  • Подход "Все – код".
  • Простота освоения и использования.

Скрипты в Renpy – это программные инструкции, похожие на Python (и даже позволяющие вставлять туда непосредственно Python). Это значит, что хранится оно в тексте, и прекрасно обрабатывается системами контроля версий.

Совместная работа, код-ревью, автоматический анализ кода – это продало мне движок.

Вот что мы сделали:
  1. Ввели четкую структуру для сюжетных скриптов: игровые дни по файлам, ветки по методам, один вход, зафиксированное число выходов.
  2. Позвали скриптера, который фулл-тайм разбирал старые визуальные скрипты и переносил их в новые, текстовые.
  3. Обложили перенос скриптов обязательным код-ревью: обновления выкатывались небольшими пачками, я проверял их на соответствие структуре и чистоту кода.
По итогу мы получили понятные, читаемые скрипты, без дублирования и с четкой структурой. Они стали управляемы. Походу вскрылся целый ряд багов и дефектов, которые до этого прятались за хаотичным визуальным сценарием.
...Да не очень

Пока сценарий делался начисто, разработка не стояла на месте.

Команды работало две: одна занималась непосредственно игрой и добавляла механики, которых с каждой итерацией становилось все больше, а вторая развивала проект Brezg Content.

Это был веб-редактор для игровых сущностей: документов, досье персонажей, писем. Нарративщики могли прямо в браузере создавать эти сущности, геймдизайнер раскидывал баланс – и все это прекрасно экспортировалось в игру в формате .json

На тот момент большая часть команды разработки – третьекурсники ЛЭТИ, по нашим меркам технология была прорывной. В какой-то момент наш бэкендер даже добавил совместное редактирования на веб-сокетах а-ля Google Docs.

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

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

На тот момент в нем было три источника строк: строки в сюжетных скриптах, псевдо-таблицы с переводами этих строк, и вынесенные нами в конфиг UI-ные строки.

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

С точки зрения планирования проекта это был апокалипсис: сроки уже жмут, движок не сменишь, как решать задачу – не ясно.
РЕШЕНИЕ – ВЫШКА

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

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

Парсер и пересборщик языка Renpy на основе LL-грамматики.

Идея была простейшая: если мы не можем соотносить строки и их переводы в скриптах, давайте пометим все строки идентификаторами. И в скрипты, и в таблицу можно вставить комментарии – чем не место для id?

Для этого пришлось написать две программы:
  1. Ту, что достает из скриптов все фразы (и позволяет отправить их на перевод, надеясь, что это не путь в никуда).
  2. Ту, что потом пересоберет все скрипты и интегрирует перевод.
LL-грамматики – это такой способ описать формальными правилами искусственный язык.

Грубо говоря, это такой язык над языками, если грамотно описать на нем код Renpy – можно читать и писать его другими программами.

Это не тривиальная задача, и я бы не пришел к этому решению, если бы не универский курс математической логики и теории алгоритмов. Профессору Сергею Николаевичу Позднякову летит мой респект.
У нас получилось не просто связать строки с их переводом, но и наладить импорт-экспорт из Brezg Content.

Система получилась пугающая, но рабочая. Я покрыл ее тестами от и до, и проблема с локализацией была устранена.
ИТОГО

  1. Мы вывезли первый релиз.
  2. Самые большие проблемы походу разработки были связаны с ограничениями и недочетами инструментов.
  3. Самые большие прорывы были связаны с написанием своих инструментов.
  4. Появилась экспертиза: что такое визуальная новелла, какие подводные камни.

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

Я взвесил все «за» и «против», и решил вернуться к Unity. Но теперь – без привязки к готовым инструментам.
ИНКВИЗИЦИЯ

OH UNITY, HERE WE GO AGAIN


Готовых решений под Unity за время работы над For the People стало больше. И они продолжали меня не устраивать.

Но у меня на руках был прототип редактора визуальных скриптов, который на одном сайд-проекте мы использовали для катсцен.

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

Основные требования были определены так:
  1. Это система визуального программирования (привет, Fungus), с которой могут работать не-технические специалисты. Их время дешевле, а в материал они погружены лучше.
  2. Исходники этих скриптов человеко-читаемы, хранятся в тексте и дружат с системой контроля версий. Автоматизация, тесты, код-ревью – все доступно.
  3. У разработчиков должна быть возможность в любой момент добавить новые ноды, а также изменить старые, не сломав уже собранные скрипты.
  4. Под капотом – асинхронщина, чтобы это было удобно программировать.
  5. Система должна уметь в импорт-экспорт локализации.
  6. Все происходит внутри Unity, прослойку в виде Brezg Content мы убрали, как слишком тяжеловесную.

К назначенным дедлайнам появляется первая версия того, что в дальнейшем станет полноценным сценарным движком поверх Unity – Loki 0.1. Не то, чтобы существовала традиция называть плагины к Unity исключительно отсылками на скандинавскую мифологию, но один из лучших плагинов называется Odin, а я в восторге от викингов – название напросилось само собой.

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

ИТОГО

  1. Получилось перейти на Unity и собрать проект.
  2. Свой инструмент был сырой, но решал поставленные задачи.
  3. Гипотезы насчет важности инструментов начинали подтверждаться.

Игра про инквизицию не получила зеленый свет, проект свернули. Пока шла подготовка к следующему препродакшену и перебирались концепты, я собрал небольшую команду внутри студии, чтобы попробовать себя в качестве гейм-дизайнера и сделать текстовый квест/JRPG.
TRUE MAGICIAN
РЕДАКТОРЫ, ДЖОННИ, ОНИ НА ДЕРЕВЬЯХ

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

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

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

Loki обновился до версии 0.2.

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

Это сильно сократило время работы программистов.

Да и сам редактор стал сильно удобнее: многое менялось по фидбэку сценариста.
Другим важным нововведением стало создание сложных редакторов прямо в Unity, пришедших на замену Brezg Content.

Используя аддон Odin, получилось в несколько раз ускорить их создание и добиться сложного поведения. Через них в игру добавлялся контент вроде противников и оружия, настраивался баланс.
ФЕСТИВАЛЬ

Мы довели проект до демки для Steam-фестиваля. Удалось проверить гипотезы на полноценном публичном релизе: автоматические сборки работают, игра не вылетает, сценарии правильно отрабатывают.

Из интересных выводов – когда инструмент становится достаточно удобным, чтобы им могли пользоваться не-технические специалисты, встает проблема обучения git и затаскивания их в процессы с код-ревью.

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

Итого
  1. Получилось довести проект до публичного релиза.
  2. Инвестиции времени в инструменты начали окупаться, как со стороны сценаристов/дизайнеров, так и со стороны разработчиков.
  3. На проекте с относительно длинным сюжетом стало понятно, что структура переходов между скриптами не менее важна, чем структура самих скриптов.
  4. Подсветилась проблема валидации данных в сценариях.

К моменту выхода демки True Magician подошел к концу препродакшн следующего большого проекта студии. Все внимание переключилось на него.

WITH GOOD INTENTIONS
УСПЕШНЫЙ УСПЕХ

Мы снова расширили команду разработки, пересмотрели подход к UI, расшили возможности редакторов.

На версии Loki от True Magician собрали первое демо, которое показало: инструменты работают хорошо, но их нужно еще немного докрутить.

Релиз второго демо состоялся вместе с релизом Loki 1.0. Были добавлены:
  • Автоматическая валидация контента.
  • Миграция между версиями скриптов.
  • Возможность вернуть из скрипта значение.
  • Закладки в редакторе.
К этому релизу стало окончательно понятно: гипотеза о пользе кастомных инструментов была верной.

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

Огромный буст к производительности дал вывод Loki из контекста проекта в отдельную библиотеку: когда ваш инструмент – независимый плагин, который игра может только расширять, вы можете синхронизировать его между двумя проектами. Обновления сценарного движка для With Good Intentions переносились в True Magician, обновления сценарного движка для True Magician переносились в With Good Intentions.

Эту модель я отмасштабировал: собрал по всем проектам вещи, которые хочется использовать в разных проектах и синхронно обновлять, вывел в Open Source, начал поддерживать scoped registry registry.khakhanov.dev

Это семейство плагинов для Unity, которое было названо Valhalla, насчитывает уже 15 библиотек. Все используются в нескольких проектах.
Loki в Open Source не выходит. Я пробовал выложить его как плагин в Unity Asset Store, но не проходил по правилам платформы.

За 2023 год, я надеюсь, удастся опубликовать. Но это не точно.
РЕЛИЗ И UNITY

With Good Intentions дошла до релиза. Когда проект разросся, вскрылось две проблемы:
  • Старая-добрая локализация, с которой снова были сложности.
  • Оптимизация.

Проблемы с локализацией были тривиальнее, чем в Renpy: штатная система импорта-экспорта падала на больших объемах данных. Опыт For the People тут помог, разработали свою систему чтения и записи таблиц. С автоматизацией, заменами и двух-сторонним объединением.
А вот с оптимизацией пришлось повозиться: проект очень долго грузился, потому что все ассеты сразу считывались в оперативную память. Звуки и графику пришлось переписать на Addressables, которые оказались довольно удобными. Сделал заметку, что на новых проектах такую систему надо внедрять заранее.
ИТОГО

  1. Полноценный мультиплатформенный релиз на проде.
  2. Инструменты сделали за нас уйму работы, думать нужно было в основном о механиках.
  3. Скорость итераций увеличилась кратно.
  4. Сравнение изменений в системе контроля версий несколько раз очень спасало, удавалось быстро отлавливать проблемы в сценарных скриптах.
  5. После проекта остались переиспользуемые библиотеки, большая часть которых вынесена в Open Source.
А ДАЛЬШЕ?

За четыре года я и мои коллеги прошли путь от "что-то все не работает, какой бы движок выбрать" до полноценных кастомных инструментов поверх Unity. Они делятся между самыми разными проектами: начиная от визуальных новелл и заканчивая заказной мобильной MMO, над которой я успел поработать.

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

Инструменты показали себя хорошей инвестицией. Время разработчиков экономится, скорость работы растет – бизнес доволен.

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

Надо ли оно вам? Зависит от проекта, но если вы играете в долгую, то скорее да, чем нет.

Сейчас я отошел от визуальных новелл.
В рамках KhanNorth Studio, чьим CEO я совершенно случайно являюсь, мы применяем все те же инструменты для создания ретро-RPG. Удивительно, как много наработок и опыта перекладываются на совершенно другой жанр: все те же библиотеки с открытым исходным кодом, все тот же сценарный движок Loki.
Думаю, за этот год многие новые наработки тоже перейдут в Open Source, особенно связанные с 3D.

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

А еще у меня твиттер есть, тоже подписывайтесь.

Khakhanov, out.
Статью подготовил:
Тимофей Хаханов
А чтобы не пропустить новые статьи, присоединяйся к нам в сообщество ВК!

INDIE SPACE

Новости, геймдев-юмор, инди-игры

Made on
Tilda