Console Punks: Haxe for Xbox, Playstation and Beyond. Dan Goldstein

В своем докладе Дэн Голдстейн поделился опытом работы над игрой Dungeon Punks, вышедшей на Xbox One, Playstation 4, Playstation Vita, PC (доступна в Steam) и веб (Flash-версия), а также рассказал о проблемах, с которыми он и его команда столкнулись в процессе портирования и выпуска игры на консолях.

Как всегда видеоверсия доклада доступна на сайте Haxe.

Dungeon Punks - Action RPG с локальным кооперативом. Это первая игра на Haxe, выпущенная на консолях.

Dungeon Punks является своего рода продолжением игры ShadowTale - web MMO на Flash, выпущенной в 2008 году. Поначалу предполагалось, что Dungeon Punks будет Free to Play мультиплеерной игрой для веб, но в процессе разработки прототипа было оказалось, что игра лучше подходит для локального коопа на консолях.

Прототип изначально писался на AS3 и использовал код из ShadowTale, но спустя 3 года разработки (где-то в январе 2015) игру перевели на Haxe, что позволило собирать игру под Flash и под Unity, благодаря чему удалось выйти и на консолях.

Трейлер игры - https://www.youtube.com/watch?v=ySOnHvQamiE

Flash-версия игры сильно урезана, в ней доступно только несколько первых уровней, а также используются текстуры низкого разрешения и сильно сжатые звуки.

Flash-версия выступает как демо для продвижения полноценного релиза в Steam.

В основном над игрой работало 2 человека: программист (в этой роли выступал Дэн) и геймдизайнер. Но на этом их роли, конечно же, не ограничивались, им приходилось заниматься и другими задачами.

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

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

Перед портированием имеющегося AS3 кода в Haxe сначала был переработан механизм отрисовки графики со стандартного Flash API на Stage3D API, для чего была написана обертка над Stage3D для реализации основных функций отрисовки 2D графики.

Затем с помощью AS3HX имеющийся код был сконвертирован в Haxe, при этом потребовалось множество доработок получившегося кода. Однако по мнению Дэна AS3HX является крайне полезным инструментом, и справляется со своей работой в 95% случаев.

После конвертации кода в Haxe была написана реализация библиотеки-обертки для Unity (работа с графикой, звуками и т.д.).

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

Использование Flash в разработке имело такие преимущества как:

  • быстрая компиляция - проект в 100k строк кода компилировался за 1-2 секунды;
  • наличие отличных инструментов для отладки приложений;
  • с помощью Adobe AIR возможно написание дополнительных инструментов, имеющих доступ к файловой системе. При этом также возможно повторное использование кода из клиента.

Однако большой проблемой было ограничение по объему видеопамяти, доступной для работы в Stage3D - всего 340 Мб. Из-за чего для flash-версии пришлось использовать текстуры низкого разрешения, а также идти на различные ухищрения в процессе разработки.

Дэн отметил, что сейчас вместо Flash он бы использовал HashLink, т.к. обладая всеми перечисленными достоинствами Flash, он избавлен от его недостатков.

Как уже упоминалось, для игры написан легковесный движок, в котором для каждой из поддерживаемых платформ реализованы следующие системы:

  • система отрисовки графики, в основном предназначена для отрисовки 2д-графики с помощью полигонов;
  • методы для воспроизведения звуков и музыки;
  • системы для реализации функций, которые есть на каждой из платформ, но работают везде по-разному: достижения, сохранения игр и настройки игры (у Sony и Microsoft свои требования и способы работы с данными функциями). Сюда же можно отнести и систему обработки пользовательского ввода: у XBox и Playstation разные геймпады, а на PC - вообще зоопарк. Поэтому для Steam-версии отдельно реализована возможность настраивать управление игрой.

Для подготовки данных для игры (тексты, данные о внутриигровых предметах, цены и т.д.) использовался Excel. Перевод данных в JSON осуществлялся с помощью написанного с использованием библиотеки ExcelDNA экспортера.

Преимуществами Excel по мнению Дэна являются: простота использования (при этом не нужно быть программистом), наличие системы навигации по данным, возможность использования формул, быстрого редактирования больших объемов данных. Также если использовать xml-формат для сохранения Excel-файлов, то такие файлы можно хранить в системе управления версий.

Хранение формул в Excel позволяет не “зашивать” их в исполняемый файл, а парсить на лету, при этом отпадает необходимость постоянной перекомпиляции клиента (при каждом изменении формулы, подгонке коэффициентов в ней) и сокращается время, потраченное на баланс игры.

Для управления JSON-файлами, полученными на выходе из Excel (а также написанными вручную), был написан “компилятор данных” (написан на Haxe, скомпилирован в Adobe AIR). Данный инструмент выполняет следующие функции:

  • осуществляет валидацию данных, находит ошибки в формате файлов;
  • для того, чтобы не дублировать постоянно данные в разных файлах и в рамках одного файла (например, скорость передвижения персонажей), был реализован ссылочный механизм между данными. При сборке “компилятор данных” осуществляет контроль за зависимостями между файлами данных, в результате получается один большой JSON-файл, в который попадают только необходимые данные.

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

Кроме того преимуществами использования формата JSON является то, что:

  • он хорошо поддерживается системами управления версий;
  • для редактирования JSON-файлов не нужны какие-либо специальные инструменты, т.к. это текстовый формат;
  • хотя JSON напрямую не поддерживает комментарии, все же в нем можно хранить документацию по формату файла, если использовать определенные соглашения (например, использовать поля с именем “documentation” или “comment”);
  • так как формат очень гибкий, то в игре он используется даже для описания самих форматов данных, которые хранятся в файлах, что позволило использовать JSON и для их валидации, реализации системы наследования и механизма ссылок между данными.

В итоге JSON используется для хранения всех возможных данных:

Валидатор данных, которые хранятся в JSON, почти полностью написан на Haxe (собирается как Adobe AIR приложение), за исключением небольшого приложения на C++, которое отслеживает изменения в файлах и запускает проверку данных, если изменения имели место.

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

Для того, чтобы избежать относительно медленного процесса парсинга JSON’ов, используются собственные сериализаторы / десериализаторы данных, способные сохранять и читать данные в бинарном формате.

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

Использование Unity в качестве библиотеки для поддержки консолей возможно благодаря работе Caue Waneck, который добавил в Haxe возможность генерации кода в C#, а также написал библиотеку UniHX. Эта библиотека анализирует dll-файлы редактора Unity и генерирует extern’ы для классов Unity, таким образом появляется возможность работы с этими классами в Haxe коде (при этом доступны проверка типов и автодополнение).

К сожалению работа над библиотекой прекращена, так как Caue переключился на Unreal Engine, но ее текущая версия вполне работоспособна, и Дэну практически ничего не нужно было изменять в генерируемом коде.

При работе с Unity из Haxe Дэн столкнулся с проблемами, связанными с Generic-классами (в C# и Haxe работа с Generic’ами отличается), например, при загрузке ассетов. Однако эти проблемы не были нерешаемыми, и для них были найдены обходные пути.

При написании библиотеки-обертки для API их игрового движки также возникли затрудения, связанные с тем, что в Unity не всегда есть прямые аналоги требуемых методов, а если они есть, то они могут оказаться не самыми производительными из доступных методов. Например, в Unity есть CommandBuffer API, которое дает доступ к списку команд для отрисовки графики. Но на тот момент, когда Дэн пробовал им воспользоваться (примерно в середине 2016 года), он показал крайне низкую производительность, поэтому от его использования пришлось отказаться.

Кроме того, когда вы нашли казалось бы подходящее вам API, которое показывает хорошие результаты на вашей машине, то не следует радоваться раньше времени, т.к. этот же код может работать гораздо медленнее на консолях, поэтому необходимо проверять производительность выбранного API везде, где его планируется использовать. Этот опыт проб и ошибок при подборе нужного API оказался наиболее болезненным в разработке игры, которая должна работать в веб, на PC, стационарных и мобильных консолях.

В качестве еще одного примера поиска подходящего решения для отрисовки графики Дэн привел реализацию цветовых трансформаций объектов, они хорошо работают во Flash, прекрасно реализуются, если вы работаете с низкоуровневым 3d API (например, в OpenGL), но в случае Unity это приводило к крайне низкой производительности. И для решения этой проблемы в Unity пришлось использовать кеширование множества объектов (материалов) в огромных пулах, где каждый объект немного отличался от других степенью градации цвета.

Кроме этого, в случае PS Vita, как наиболее слабой консоли, было необходимо ограничивать общее число draw call’ов (это актуально и для других мобильных платформ).

Дэн также отметил, что отладка C# кода, сгенерированного из Haxe, возможна, но это не самое приятное занятие, особенно если сравнивать с отладкой Flash. Поэтому он старался избегать этого :)

Кроме описанных проблем, связанных с использованием Haxe, также есть проблемы, связанные непосредственно с Unity:

  • есть ряд функций (обработка пользовательского ввода, реализация сохранений игр, работа с учетной записью пользователя), которые по идее должны быть реализованы в Unity, но так как работа с этими функциями на разных консолях значительно отличается, то в Unity они просто не реализованы. И вам нужно самому искать решение для этих проблем;
  • также есть ряд проблем, связанных с тем, что разные версии Unity могут вести себя совершенно по разному. Например, в следующей версии может быть решена какая-либо проблема, с которой вы столкнулись, она может работать стабильнее, но в ней может быть сломан функционал, на который вы рассчитываете. Особенно это актуально в тех случаях, когда вы используете Unity нестандартным образом (как в случае Дэна, когда он использовал Unity, как библиотеку для поддержки различных платформ, а не как игровой редактор и движок). Также может возникнуть проблема совместимости между версией Unity и библиотеками, специфичными для какой-либо консоли (то есть необходимо искать или ждать выхода совместимых версий библиотек и Unity). И, наконец, производительность игры может сильно варьироваться в зависимости от того, с какой версией Unity вы работаете (в особенности если Unity используется нестандартным путем). Поэтому Дэн старался по возможности не обновляться, но полностью избежать этого ему не удалось.

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

Все подробности рассказать он не смог, так как они находятся под NDA (соглашение о неразглашении), однако, его доклад дает общее представление о процессе разработки под консоли. Если вам интересна эта тема, то могу посоветовать еще один доклад с о портировании игр, написанных на Unity.

У компаний-платформодержателей (Microsoft, Sony, Nintendo, Valve) разный подход к взаимодействию с разработчиками, но Дэн дал ряд общих советов по этой теме:

  • крайне желательно найти работника компании (например, встретить на конференции или выставке), с которым можно наладить общение. Это сильно упростит процесс взаимодействия по сравнению с формальным путем;
  • также следует найти человека в компании, который занимается взаимодействием с инди-разработчиками, и который мог бы отстаивать интересы вашей игры. Такое знакомство может дать вам существенные преимущества;
  • в процессе общения с компанией нужно быть активной стороной и постоянно идти на контакт. Связано это с тем, что разработчиков игр много, а число работников компании, ответственных за взаимодействие с ними, невелико, поэтому про вас часто могут просто забывать. Но не стоит принимать это лично, нужно понять, что время работников компании ограничено.
  • если вам удалось выпустить игру на консоли, то это никак не гарантирует вам продаж игры. Хотя на консолях игр выходит гораздо меньше, чем в Steam или в AppStore, но спустя несколько часов после релиза ваша игра может затеряться среди других инди-игр и множества дополнений к крупным проектам.
  • поэтому нужно периодически пытаться договориться о продвижении игры в сторе;
  • в случае, если у вас возник вопрос технического характера, то у вас есть два варианта: создать тикет и ждать, когда кто-нибудь на него ответить или попытаться найти решение на закрытых форумах для разработчиков под NDA. В случае Дэна такие форумы (в том числе форум Unity) оказали неоценимую помощь.

Далее Дэн рассказал о деталях процесса сертификации. Не пройдя сертификацию вы не сможете получить доступ к SDK и DevKit’ам, то есть не сможете даже приступить к портированию игры.

Процесс сертификации подразумевает оформление множества документов и заполнения огромного количества форм на веб-сайтах платформ.

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

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

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

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

Когда игра близка к релизу понадобится подготовить материалы для ее размещения в сторах:

  • трейлеры и видео игрового процесса. Эти видео также проходят процесс одобрения, т.к. к ним также предъявляются определенные требования. Например, логотип ESRB необходимо показать до того, как будет показан игровой процесс, он должен показываться определенное время, иметь требуемый размер и располагаться на экране в определенном месте и т.д.;
  • игровые скриншоты;
  • описание игры, при этом желательно чтобы оно было переведено на языки регионов, где игра будет выпущена (иначе игроки ничего не поймут);
  • региональные цены;
  • прочие метаданные для магазина. Например, нужно указать, хотите ли вы чтобы страница игры отображалась в магазине до релиза, будет ли доступен предзаказ и т.д.

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

Важно помнить, что всю эту работу нужно проделать для каждой платформы, на которой вы собираетесь выпустить игру, а иногда даже для каждого региона!

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

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

Также одна и та же игра может получить разные возрастные ограничения в разных регионах, это также нужно учитывать. В Dungeon Punks, например, пришлось удалить всю кровь для европейской версии игры.

И конечно вам потребуется предоставить рейтинговым организациям материалы для оценки:

  • скриншоты;
  • видео игрового процесса;
  • финальный билд игры;
  • в зависимости от игры, возможно придется также предоставить видео всех кат-сцен и тексты диалогов.

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

  • то, как пользователь взаимодействует с игрой (поведение меню);
  • визуальные требования (расположение элементов интерфейса);
  • требования к брендингу - очень строгие. Например, есть точные указания как и где нужно располагать знаки ™ и ®;
  • требования к использованию API (как часто можно вызывать определенный метод, где разрешается сохранять данные и т.д.).

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

Для проверки соответствия этим требованиям имеются автоматизированные инструменты.

Так как требований, предъявляемых к игре, множество, то сам процесс сертификации может занять длительное время - с первого раза пройти его обычно не удается. И это также необходимо учитывать. В качестве примера Дэн рассказал о разработчике, с которым он встретился на выставке PAX East - для него процесс сертификации игры на Xbox One растянулся на целых 8 месяцев, хотя сама игра технически была готова и оттестирована.

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

Далее Дэн рассказал о проблемах с производительностью в C# коде, сгенерированном из Haxe:

  • в некоторых местах неожиданно используется Dynamic, например, при использовании необязательных параметров в методах;
  • метод Std.is() довольно медленный;
  • инициализация переменных на Flash и в C# осуществляется по разному, что может привести к неожиданному поведению и к падениям приложения;
  • в неожиданных местах могут создаваться “мусорные” объекты, после чего при сборке этого мусора в игре проседал фпс. В качестве примеров кода, генерирующего мусор, Дэн назвал использование замыканий, преобразования Float в String.

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

Также Дэн отметил, что к сожалению C# код компилируется в разы дольше, чем Flash.

При разработке под консоли на Unity также нужно иметь в виду следующие моменты:

  • ограниченность объема оперативной памяти, особенно на мобильных консолях. Поэтому необходимо стараться избегать генерации “мусора”, занимающего память;
  • сборка проекта под консоли занимает значительное количество времени (особенно если сравнивать со сборкой под Flash) - в случае Dungeon Punks оно достигало 15-30 минут. К этому времени также стоит добавить время, необходимое для загрузки билда на DevKit;
  • так как для компиляции проекта Unity использует специфичный для каждой из платформ компилятор C++, то с ним также могут возникнуть неожиданные проблемы. Например, компилятор может просто зависнуть, не справившись со сгенерированным C++ кодом, при этом никакой индикации о проблеме не будет.

Подводя итоги, Дэн отметил, что несмотря на все перечисленные проблемы, использование Unity очень сильно помогло при разработке игры под консоли. После того, как у него на руках были билды игры для Playstation 4 и Vita, ему с первого раза удалось запустить игру и на Xbox One.

Также на форумах Unity вам могут помочь в решении часто возникающих проблем.

Однако, если у вас возникла очень специфичная проблема, то решить ее скорее всего придется самому, возможно написав для этого плагин на С++.

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

Главные моменты, которые необходимо иметь в виду при разработке игры на Haxe под консоли:

  • использование Haxe позволило повторно использовать код и игровом клиенте и в инструментах;
  • использование бинарных файлов для хранения данных помогло ускорить чтение данных с диска;
  • сериализация бинарных данных работает быстрее и требует меньше памяти, чем парсинг JSON. Однако это не запрещает вам работать с JSON при разработке игры, бинарный формат можно использовать только в самом клиенте;
  • необходимо избегать генерации мусора на устройствах с малым объемом оперативной памяти;
  • при расчете сроков релиза игры необходимо учитывать время на прохождение сертификации и также время на работу с прессой (подготовка ключей и время на написание обзоров);
  • быть готовым к тому, что придется самостоятельно реализовывать функции, специфичные для каждой из платформ (например, сохранения игр);
  • быть готовым к большому объему работы по заполнению документации;
  • необходимо постоянно инициировать контакт с платформодержателями, чтобы получить лучшие условия по продвижению игры в магазине.

Говоря о следующем проекте, Дэн предположил, что использовал бы для него связку HashLink и Heaps, так как эта комбинация обладает следующими плюсами:

  • код Heaps легко понять и в него также легко вносить собственные изменения;
  • Heaps поддерживает WebGL;
  • довольно быстрая компиляция проектов;
  • обладает всеми достоинствами Flash, но работает на большем числе платформ;
  • имеются инструменты для отладки;
  • есть поддержка консолей. При этом Дэн избавится от необходимости использовать Unity, то есть перейдет от цепочки (Haxe -> С# -> С++) к (Haxe -> C).
  • также ожидается, что Николас создаст VM-версию HashLink, сборка под которую не будет занимать столько времени, как сборка релиза на консоли. Таким образом значительно сократится время тестирования игры на консолях;
  • возможно Дэн будет использовать CastleDB для работы с некоторыми игровыми данными.