Стек технологий Shiro Games

Автор оригинала: Nicolas Cannasse
  • Перевод

Наш игровой движок Heaps.io и набор инструментов и технологий, на котором он основан, являются результатом опыта, накопленного за двадцать лет, посвященных созданию игр: сначала в компании Motion-Twin (создатели Dead Cells), а с 2012 года в Shiro Games (Evoland, Northgard и Darksburg).
Названные игры (2D и 3D) были созданы с использованием стека библиотек и инструментов, исходный код которых был открытым с самого начала, и которые продолжают развиваться и поддерживаться.
Так как меня часто спрашивают о том, как мы создаем игры, то я подумал, что было бы неплохо поделиться подробностями обо всех элементах технологического стека Shiro Games. Он прекрасно подходит для наших задач, так что возможно он может подойти и другим компаниям.


image


Сообщество Haxe / Heaps


Если у вас есть какие-либо вопросы или вы просто хотите обсудить представленные в этой статье технологии, вы можете связаться с сообществом Haxe / Heaps:



Нативный слой


image


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



Основным компонентом этой стратегии является виртуальная машина HashLink — быстрая строго типизированная виртуальная машина для языка программирования Haxe. Ее можно сравнить с JavaVM или Mono (используется в Unity), но при этом HashLink VM больше ориентирована на игры в реальном времени.


Игра компилируется в кроссплатформенный файл .hl, который можно запустить с помощью HashLinkVM JIT. Также байткод HashLink может быть сконвертирован напрямую в код на C, который затем можно скомпилировать с помощью любого компилятора — такой путь мы используем для консольных портов наших игр для PlayStation, Xbox и Nintendo Switch.
HashLink VM отлично работает как для классического объектно-ориентированного, так и для функционального стилей программирования. Она хорошо себя показывает в вычислениях с плавающей точкой, что важно для игр. Также данная виртуальная машина была разработана таким образом, чтобы дополнительные затраты памяти для работы сборщика мусора были минимальными. Например, наша 3D-игра Northgard использует менее 500 МБ памяти.


Так как HashLink — виртуальная машина, то это значит, что для вашей игры (или приложения) не будет различия между отладочной и релизной сборками (только если вы не скомпилируете свой код в C), игра всегда будет работать так же, как и на компьютерах игроков, на полной скорости, и при этом всегда можно будет получить полный стек вызовов.


Нативные библиотеки


Хотя HashLink поставляется только с небольшой стандартной библиотекой, ее возможности могут быть расширены с помощью дополнительных библиотек (написанных на C), предоставляющих доступ к новым API. Написание таких библиотек потребует от разработчика некоторых знаний об устройстве виртуальной машины и о том, как работать со сборщиком мусора, но это довольно несложный процесс. При правильной реализации можно легко изолировать ошибки, возникающие на низком уровне, от ошибок в логике приложения.


На данный момент с HashLink распространяются такие нативные библиотеки как: SDL2, DirectX11, OpenAL (работа со звуком), LibUV (сокеты), SSL (шифрование) и FMT (для работы с Zip, Ogg, Png, Jpg) а также ряд библиотек для работы с другими форматами файлов.
Исходный код перечисленных библиотек открыт и является частью репозитория HashLink.


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


Нативные инструменты


Низкоуровневые инструменты необходимы для анализа производительности разрабатываемых приложений. В Shiro Games мы используем следующий набор инструментов:


  • В HashLink VM есть встроенный отладчик, имеющий интеграцию с Visual Studio Code
  • Для анализа использования CPU недавно был разработан HashLink CPU Profiler. Работа данного профилировщика не замедляет работу анализируемого приложения на HashLink
  • Для измерений потребления памяти и обнаружения утечек, вы можете либо замерить все выполненные аллокации, либо сделать дамп памяти для последующего анализа с помощью Memory Profile API (к сожалению данное API на данный момент не задокументировано)
  • Для измерения производительности графической подсистемы мы используем инструменты, предоставляемые вендорами GPU, например, NVIDIA Nsight.

Уровень языка программирования


image


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


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


Конечно, как главный разработчик языка Haxe, я немного предвзят, но каждому программисту в Shiro действительно нравится работать с Haxe, и это критически важный инструмент для нашей повседневной работы. Кроме того, мы наняли разработчиков с различным опытом программирования (C++, C#, JavaScript, Python, Java и т.д.), и все они смогли быстро адаптироваться к Haxe и писать эффективный код.


Haxe — это кроссплатформенный язык программирования, который может компилировать код под множество различных платформ. В Shiro мы используем в основном две платформы: HashLink для наших игр и JavaScript для наших инструментов (подробнее об этом далее).
Некоторые популярные инди-игры также были созданы с использованием Haxe (но без HashLink или других представленных в данной статье инструментов), например: Papers Please, Brawlhalla, Dicey Dungeons и др.


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


Узнать больше о Haxe вы можете на его официальном сайте.


Игровой движок: Heaps.io


image


Heaps.io — игровой движок, лежащий в основе игр Shiro Games. Он обеспечивает:


  • 2D рендеринг
  • 3D рендеринг
  • Обработка звука
  • Управление (клавиатура, мышь, геймпад)
  • Управление ресурсами.

Он построен так, чтобы отделить реализацию низкоуровневых функций для поддержки платформ от графической логики / данных среднего уровня. Такая архитектура позволяет интегрировать новый рендерер или поддержку новой платформы — для этого достаточно просто портировать несколько классов (при условии что у вас уже есть соответствующие нативные библиотеки для HashLink). На данный момент Heaps.io поддерживает следующие платформы / графические API:


  • HashLink и DirectX11
  • HashLink и OpenGL / SDL2
  • HashLink / C и NVN (нативное графическое API в Nintendo Switch SDK)
  • HashLink / C и GNM (нативное графическое API в PS4 SDK)
  • HashLink / C и Xbox One SDK
  • JavaScript и WebGL2

Примечание: обозначение "HashLink / C" означает, что для указанной платформы возможно использовать только компиляцию из байткода HashLink в C (JIT VM на данных платформах не доступен).


image


Heaps.io задумывался как легковесный движок, который можно легко адаптировать под нужды пользователей. Он предоставляет 2D / 3D граф сцены, и поведение каждого объекта на сцене можно доработать. Рендерер и система освещения также могут быть полностью заменены, что позволяет написать собственный конвейер рендеринга, отвечающий требованиям конкретной игры.


И 2D и 3D используют аппаратное ускорение на GPU и основаны на GPU-шейдерах. Heaps поставляется с собственным встроенным языком шейдеров HxSL. HxSL — мощный инструмент, поскольку вместо необходимости написания одного большого шейдера он позволяет написать отдельные небольшие шейдерные эффекты, которые затем собираются вместе и оптимизируются во время выполнения программы.


Система управления ресурсами в Heaps.io вынесена в отдельный расширяемый фреймворк. Кроме того, Heaps.io предоставляет средства для «запекания ресурсов» — автоматической конвертации и упаковки ресурсов в более подходящий для движка формат (например, для ресурсов, получаемых на выходе из Photoshop, Maya, Blender и т.д.)
Больше информации о Heaps вы найдете на его официальном сайте, в разделе документации.


Редактор HIDE


image


HIDE (Heaps IDE) — это отдельное приложение, которое позволяет создавать средства для просмотра и редактирования 2D / 3D-контента.
HIDE — это HTML5-приложение, в котором запущен инстанс движка Heaps.io в режиме WebGL2, что позволяет очень быстро разрабатывать пользовательские интерфейсы, используя Haxe и HTML / CSS.


На данный момент HIDE предоставляет следующие средства:


  • древовидный список ресурсов
  • просмотрщик 2D текстур
  • просмотрщик 3D моделей в формате FBX и редактор материалов
  • редактор 2D и 3D эффектов на основе временной шкалы (timeline based effects)
  • редактор 2D и 3D частиц
  • редактор 3D-уровней (на скриншоте ниже показан уровень Darksburg)
  • редактор Префабов
  • редактор скриптов (с использованием hscript)
  • редактор графа шейдеров [работа над ним пока что не окончена]

image


HIDE ориентирован на обработку данных (data-oriented) и основан на модели Префабов (класс hrt.prefab.Prefab). Эта модель хранит данные редактора и может по запросу создавать экземпляры эффектов, уровней и т.д.; также она является поставщиком данных для движка, который затем обрабатывает их в соответствии с заложенной вами игровой логикой.


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


Исходный код HIDE разделен между пакетами hide (содержит код IDE), и hrt (содержит классы, которые можно использовать как часть игрового клиента).


К сожалению, в настоящий момент документация для HIDE практически отсутствует и мне еще предстоит поработать над ней.


DomKit UI Toolkit


image


DomKit — это наш фреймворк для написания компонентов пользовательского интерфейса. На данный момент это самое последнее дополнение к нашему технологическому стеку, поэтому он все еще дорабатывается.
Он позволяет описывать пользовательский интерфейс с помощью XHTML-разметки непосредственно в коде игры, что обеспечивает возможность напрямую связывать строго типизированные данные с логикой игрового процесса. Кроме этого, в DomKit есть возможность стилизации интерфейсов с помощью CSS, прямо как в веб-разработке.


Используемая семантика CSS частично соответствует стандартам HTML5, но модель разметки специфична для Heaps.io и больше подходит для UI / UX в играх.


image


Также вы можете объявлять собственные компоненты, добавлять дополнительные свойства и код, описывающий как CSS должен применяться к свойствам ваших компонентов.
Кроме того, библиотека DomKit полностью автономна и может использоваться совместно с любыми UI фреймворками (но в Heaps.io поддержка DomKit уже реализована).
Узнать больше о DomKit вы можете из его документации.


Castle DB


image


Castle DB — один из самых важных инструментов для повышения производительности, который используется в Shiro Game. Это статическая структурированная база данных, с которой работают наши геймдизайнеры — редактируют все данные, используемые в игре (списки предметов, локаций, NPC, деревьев технологий, навыков и т.д.).


Используя IDE Castle DB, можно задавать и изменять структуры данных, а затем вводить данные в соответствии с описанием этих структур. В этом отношении IDE Castle DB является своего рода специализированным редактором электронных таблиц для игр.


image


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


// Data.hx
private typedef Init = haxe.macro.MacroType<[cdb.Module.build("data.cdb")]>;

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


Castle DB раньше был отдельным редактором (его старую версию можно скачать с его веб-сайта), но теперь он интегрирован в HIDE, благодаря чему можно использовать данные CDB для Префабов в редакторе уровней и т.д.


Узнать больше о Castle DB вы можете на сайте castledb.org.


HScript


image


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


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


image


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


HScript также интегрирован в CDB / Hide, что позволяет назначать объектам скрипты и т.д.
Исходный код библиотеки доступен на github, а установить ее можно с помощью команды haxelib install hscript.


HxBit


image


HxBit — это библиотека для сериализации и сетевой синхронизации. Она позволяет помечать свойства ваших классов, которые должны быть сериализованы (для сохранения) и / или переданы по сети при их изменении (для многопользовательских игр).


Полная документация доступна в вики.


MPMan


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


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

Заключение


Вот и все (пока). Я надеюсь, что после прочтения этой статьи у вас сформировалось некоторое представление о том, как мы делаем игры в Shiro. Также я надеюсь, что заинтересовал вас попробовать некоторые, если не все, из представленных инструментов.


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


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


Все инструменты в описанном технологическом стеке использовались в реальных проектах и используются для разработки еще не анонсированных игр. Они достаточно стабильны, без серьезных проблем, но, конечно, всегда есть возможность найти баги для какого-то конкретного случая. Поскольку я работаю над несколькими проектами одновременно, то мне не всегда удается быстро ответить на сообщения о найденных ошибках или пулл-реквестах, но по крайней мере у вас есть все исходники и, следовательно, возможность самостоятельно все исправить. Одна из вещей, которые лично мне больше всего не нравятся — это ситуации, когда нет возможности понять / исправить найденные ошибки.


Наконец, хочу упомянуть, что Shiro Games активно ищет разработчиков для работы над увлекательными, но еще не анонсированными проектами. Вы можете связаться со мной в Twitter и посмотреть список наших вакансий.

Комментарии 9

    +1
    но при этом HashLink VM больше ориентирована на игры в реальном времени
    Хотелось бы про это подробнее почитать. Особенно в сравнении с Unity.
    Она хорошо себя показывает в вычислениях с плавающей точкой, что важно для игр
    Точнее? Быстрее считает?

    Ещё интересно, что там за физически движок.

    P.S. занятно, что они позиционируют его как «игровой движок», хотя по факту это, скорее, фреймворк.
      0
      но при этом HashLink VM больше ориентирована на игры в реальном времени


      Хотелось бы про это подробнее почитать. Особенно в сравнении с Unity.


      Unity — это набор библиотек/инструментов и ипользование VM .NET.
      А HashLink VM — это просто VM.

      Если уж сравнивать Unity как совакупность то не с голой HashLink VM, а с Heaps.io и пр. обертками.
        0
        Unity я имел ввиду именно в контексте виртуалки и Mono.
        0

        Сравнений с Unity я нигде не нашел. Но автор оригинала также является автором HashLink, так что могу предположить, что он проектировал VM с этим расчетом
        По поводу скорости работы и вычислений могу только сказать, что ее достаточно для работы упомянутых игр на Heaps.io (они выходили на Nintendo Switch, XBox и Playstation, а Dead Cells должен выйти этим летом и на Android)
        В качестве физического движка можно использовать Bullet

          0
          «игровой движок», хотя по факту это, скорее, фреймворк.

          а в чем принципиальная разница?

            0

            Копипаста с gamedev.ru:


            Фреймворк (англ. framework — каркас, структура) — структура программной системы; программное обеспечение, облегчающее разработку и объединение разных компонентов большого программного проекта. Можно также говорить о каркасном подходе как о подходе к построению программ, где любая конфигурация программы строится из двух частей: первая, постоянная часть — сам фреймворк, не меняющийся от конфигурации к конфигурации и несущий в себе гнезда, в которых размещается вторая, переменная часть — сменные модули (или точки расширения).
            Фреймворк накладывает некие ограничения на структуру программы, и пользователю предлагается его расширять до достижения требуемого результата.


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


            Таким образом, фреймворк — это только общая структура будущей игры, каркас, вокруг которого она будет нарастать. В качестве примеров фреймворков можно привести LibGDX, Love2D
            А движок — более сложная система, состоящая из множества специализированных модулей (физика, анимация, редакторы, просмотрщики ресурсов и многое другое). Иногда движки затачиваются под разработку игр определенных жанров (или по крайней мере лучше подходят для них). Примеры движков: Unity3D, Unreal Engine, движки попроще — GameMaker, Stencyl

              0

              Звучит как "нет редактора — не движок". Что одно штука с дырками, что другое — сиди расширения свои надстраивай. Где-то батарейки уже в комплекте, разной степени заменяемости, а где-то без, что собственно не мешает поставить свои.

                0

                Я написал, что движок может включать в себя редактор, но это не обязательно.
                Да, согласен, что четкой границы между фреймворками и движками не провести. Дело в этой самой степени заменяемости батареек.
                Но где-то эта граница все-таки есть, может быть она субъективная. Но назвать Unreal Engine фреймворком, a LibGDX — движком я себя никак не смогу заставить.
                Но вообще это тема больше для холиворов как мне кажется.

          0
          Удалено (не заметил что перевод).

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

          Самое читаемое