Платформер на XNA / KNI для Яндекс Игр

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

Игра Snowtime Delivery
Игра Snowtime Delivery

Введение

Всё началось с того, что на днях я хотел попробовать сделать игру на каком-нибудь фреймворке, например, heaps.io или raylib, чтобы еще на Яндекс Играх запускалось. Но был один фреймворк, который мне всегда нравился и на который я никогда не решался разрабатывать, потому что у него не было поддержки браузеров, это был MonoGame (в прошлом XNA). И в интернете я часто слышал упоминание KNI, который якобы добавил поддержку браузеров в MonoGame и это я захотел проверить.

Я не сошел с ума, чтобы потратить время на написание игры, которая скорее всего будет работать проблемно, т.к. очевидно, что KNI вряд ли сделает хорошую поддержку браузеров (и это отчасти оказалась правда). Поэтому у меня закралась мысль поискать в сети игр с открытым исходным кодом, посмотреть, может найдется что-нибудь интересно. Забегая вперед, скажу, что с MonoGame оказалось достаточно просто найти проекты с исходниками, а вот я потом поискал по heaps.io и raylib и ничего не нашел.

В какой-то момент я обнаружил, что игры с открытым исходным кодом можно найти на itch.io. И там я нашел одну игру, платформер, мне как раз нравятся платформеры. Игра называется Snowtime Delivery. Я немного поиграл и понял, что игра нормальная и её продолжительность больше 10 минут, что должно быть по правилам Яндекс Игр. А на Яндекс Игры я и хотел портировать эту игру, т.к. это и есть самое интересное, не только проверить поддержку браузеров, но и оценить насколько комфортен фреймворк для работы с Яндекс Играми.

Об игре

Альтернативное название игры — «Снеговик на доставке». Это обычный платформер, в котором можно бегать, прыгать и приседать. По сюжету была сильная метель и письма разнесло по всему городу, снеговик решил их найти и отнести обратно. Нужно уворачиваться от препятствий, собирать письма и затем идти к почтовому ящику. Всё. Игра проходится за 15 минут.

Геймплей одного уровня

Коротко, что такое KNI

Если коротко, то раньше был такой фреймворк XNA. Фреймворк означает, что это не готовый движок и много придется дописывать самому. Затем поддержку XNA остановили Microsoft и появился форк MonoGame. А затем какой-то умелец сделал форк MonoGame и назвал его KNI, увеличил производительность и добавил поддержку браузеров.

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

На MonoGame, например, вышли такие хиты как FEZ, Celeste, Explaining every string и другие.

KNI

Оригинальный проект на самом деле сделан мягко говоря грязно, всё максимально примитивно, но оно работает и по факту играется весело, а разве это не главное? В общем я скачал репозиторий, почистил код, запустил его — всё работает. Настало время проверить KNI.

С KNI проблем никаких не было, с их репозитория скачиваешь установщик и в Visual Studio появляются шаблоны для программ. Выбираешь шаблон, где все платформы (андроид, веб, десктоп, винда) и создаешь проект. Я сразу же проверил, как запускается игра в браузере и она запускается без проблем - всё работает. Точнее, запускается без проблем пустой проект.

KNI использует технологию Blazer, я на самом деле плохо понимаю, что это такое, но немного знаком, пробовал написать тестовое приложение на Blazer и в принципе в двух словах Blazer позволяет программистам писать под веб на C#. Он компилирует код в WebAssembly и запускает в браузере.

Но Blazer это не просто компилятор, а это технология, которая позволяет удобно писать веб приложения, т.к. для вас доступны уже написаны готовые компоненты. Но для KNI знать этого ничего не нужно, достаточно понимать, что в проекте лежит файл index.html (куда можно вставить любой код на яваскрипте) и Index.razor.cs в котором происходит подключение и запуск основного класса игры на C# или XNA.

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

Проблемы поддержки веб платформы

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

  1. Не работает чтение файлов из ресурсов. В вебе не доступны функции ввода вывода для работы с файлами, потому что файлы находятся на сервере, а не на жестком диске, поэтому нужно их скачивать из сети. Если в контент билдере стоит галка “копировать” у ресурса, его нужно скачать из сети. Например вот здесь я вынес эту обработку. Но как считать директорию в ресурсах в веб билде я еще не разобрался, прошлый код переписал и вынес всё нужное в константы.
  2. Не поддерживают геймпады в вебе. Пришлось функции для работы с геймпадом внести под дефайны, т.к. выбрасывается исключение.
  3. Музыка не запускается автоматически, нужно кликнуть на экран. На самом деле это везде так, просто в KNI нет никаких проверок и тяжело понять играет ли сейчас музыка и как её запустить, когда пользователю разрешили проигрывать музыку. В итоге я сделал хак и запускал музыку, через задержку, после того как пользователь нажал на экран.
  4. Не работает поддержка касаний на мобильных устройствах. На самом деле в коде KNI вроде все нормально, кажется, что все поддерживается, но я так и не смог заставить их работать обычным способом, пришлось создавать обработчики в яваскрипте и вызывать их в C# коде.
  5. Проблемы с масштабируемостью окна в вебе. Некорректные значения у рисуемой видимой области из-за чего игра масштабируется странно. Это появляется если выставить канвасу определенный размер. Если этого ничего не трогать и сделать, чтобы ваша игра была всегда на полный экран, то проблем с масштабируемостью может не быть. Проблемы с масштабируемостью легко видны на счетчике FPS, его можно включить нажав F и изменить размер окна браузера и он покосится.
  6. MediaPlayer работает через HTMLAudioElement, из-за чего отображается системный плеер. По этой причине мне в первый раз отклонили игру, т.к. это не соответствует пункту 1.6.1.6 правил Яндекс Игр. В итоге я не стал использовать MediaPlayer и написал свои функции на яваскрипте, которые имитируют его работу. Сначала я переписал все на Web Audio API (через decodeAudioData) и всё работало нормально, уже не показывался системный плеер, но музыка запускалась не сразу из-за декодирования. Пришлось зарание скачивать музыку, декодировать её, а уже когда надо запускать, из-за чего появилась сильная задержка перед запуском игры. Оставил так, потому что с задержкой ничего не поделать. Подсмотрел в исходники Phaser, они тоже делают через Web Audio API, без HTMLAudioElement. (Хочу еще добавить, что мне не удалось убрать системный плеер при использовании HTMLAudioElement как я не пытался. Пришлось разбираться с Web Audio API.)

Что я изменил и добавил:

  1. Изменил стартовый экран, т.к. в нем была ссылка на репозиторий KNI, а по правилам Яндекс Игр никаких ссылок быть не должно. Плюс мне захотелось его немного визуально другим сделать.
  2. Добавил поддержку Instant Games Bridge, т.к. он легко позволил бы мне запускать игру и на itch.io и где угодно.
  3. Добавил поддержку Yandex Metrika на всякий случай.
  4. Добавил поддержку Яндекс Игр: определение языка, определение платформы, лидерборды.
  5. Добавил, чтобы приложение останавливало музыку, если оно неактивно (через Instant Games Bridge).

Что еще я не пробовал:

  1. Запись файлов и сохранения. Думаю, что Instant Games Bridge получится сохранять файлы, а как без него делать, пока не знаю.
  2. Полноэкранная реклама. Думаю подключить её не составить труда. просто я этого не делал, т.к. проекту она не нужна.

Выводы

Со всем проблемами я как-то разобрался и готовый результат вы можете потрогать. Игра работает в браузерах на компьютере и на мобильном телефоне.

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

Еще веб билд весит 14 мб в архиве, а в консоли Яндекс Игр отображается 23 мб. Еще это не точно, но кажется, что веб билд немного подтормаживает, нежели чем запускать не в браузере. Ещё заметил долгую загрузку билда на itch.io с подвисанием.

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

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

Но с другой стороны, например, на Unity всё работает без танцев и сразу же, поэтому я бы с осторожностью смотрел в сторону XNA для выпуска игры на Яндекс Игры, но сделать теперь это можно. И если у вас есть готовый проект на XNA, то это даже интересно.

Ссылки

33
2 комментария

Видел пару раз упоминание сборки для веба на сайте Monogame, но непонятно, насколько это рабочая вещь. Вроде бы, proof of concept.

А насчёт heaps: попробуй спросить в дискорде Haxe; всё коммьюнити вокруг языка похоже ушло туда.

1

Спасибо, полезная информация по heaps!