Особенности разработки игры для браузера
Для образовательного проекта Банка России мы сделали яркую веб-игру «Тайна потерянной копилки». Она привлекает внимание школьников к теме финансовой грамотности, знакомит с терминами, учит разумно распоряжаться деньгами. Игра понравилась не только детям, но и взрослым из разных городов России — в неё сыграли более 30 000 человек.
Мы долго просили нашего техлида рассказать о том, как происходила разработка веб-игры. Он не только рассказал, но и написал огненную статью о нашем опыте в этом проекте, о возникших сложностях, а также поделился лайфхаками в разработке браузерных игр. Получился насыщенный полезностью материал. Читайте.
Веб-игра принципиально отличается и от обычной компьютерной игры и от обычного сайта в браузере. Обычной игре все игровые ресурсы доступны оффлайн, игровому движку известны сведения о процессоре, памяти и видеокарте компьютера. Обычному сайту требуется немного ресурсов компьютера, а в случае неполадок, можно просто перезагрузить страницу.
Предположения об особенностях браузерной игры у нас были — значительные ограничения на доступный и используемый размер оперативной памяти (в ТЗ, например, зафиксировано, что для мобильных устройств должно хватать 1 Гб оперативной памяти), баланс между качеством игровых ресурсов (изображения, текстуры, спрайты, звуки, видео) и скоростью их скачивания.
К этому добавились требования от клиента — игра должна запускаться и работать во всех заявленных мобильных и десктопных браузерах (включая IE 11), на минимально возможных аппаратных характеристиках. Требования эти исходили из того, что игру предполагалось показывать при любой удобной возможности, на любом попавшемся под руку устройстве — например, в школе.
Как выбирали движок
У нас уже был опыт игровой разработки, поэтому направления выбора движка обозначили сразу:
- Игровой движок Phaser — мы уже реализовывали на нём игру для Эльдорадо/Майкрософт.
- Unity с возможностью экспорта игры в Web — мы делали игровые проекты на этом движке.
- Также рассматривали малоизвестные нам движки LibGDX, Godot, PlayCanvas.
Неизвестные варианты отвалились по вполне очевидной причине — их надо было осваивать и изучать, что, некоторым образом, пугало, хоть и не казалось невозможным. Вариант с Unity отвалился потому, что ограничения движка и экспорта не позволяли, например, использовать аудио в IE 11. А ещё потому, что экспортируемый из Unity код Javascript получался очень большой, а IE 11 значительно более медленный в парсинге и исполнении кода, чем современные браузеры.
Таким образом, было решено взять свежую версию движка Phaser (на момент начала разработки это была версия Phaser 3.11). Выбрали этот движок ещё и потому, что вся логика и отрисовка — программные, а значит, мы могли контролировать в коде абсолютно любой аспект будущей игры.
Как писали
В начале у нас не было проработанных механик, но было известно, что это точно будет платформер. Поэтому мы решили собрать хоть какой-то прототип, чтобы освежить свои знания по движку, а также сделать приблизительные замеры по потребляемым ресурсам и нагрузке на браузер.
Взяли из готовых в документации примеров «перемещение персонажа» и «тайловая карта», собрали, запустили — работает: персонаж ходит, прыгает, перемещается по платформам. Запустили во всех доступных устройствах — всё ещё работает. Добавили виртуальные кнопки управления из примера «виртуальные кнопки» и запустили на мобильных — всё ещё работает. Добавили немного механик — удар, враг, нанесение и получение урона, сбор монет — для прототипа было достаточно.
В прототипе даже чуть больше было, чем надо. Например, была реализована механика управления двумя персонажами, между которыми можно было переключаться в любой момент.
После успешного прототипа у нас появилось понимание, как будет реализована архитектура и организован код. Если говорить про инфраструктурную часть, то это работа с движком в части загрузки ресурсов, создания игровых объектов, переключения экранов. Что касается непосредственно игровой логики — это реализация персонажей, реализация механик взаимодействия с добычей, ловушками, врагами.
Стек разработки был взят довольно типичный для подобного проекта — webpack, webpack-dev-server, babel, babel/preset-typescript.
Какие трудности были
С трудностями столкнулись в соблюдении требований по производительности и в командном взаимодействии. Приходилось работать с новыми инструментами и передавать друг другу материалы в новых форматах, поэтому не всегда всё получалось гладко с первого раза.
Например, в ТЗ было предусмотрено, что игра при запуске пытается определить производительность устройства, и в случае низкой производительности отображается соответствующее уведомление. На данном этапе мы столкнулись с двумя проблемами. Во-первых, браузер не даёт практически никаких сведений на этот счёт. Во-вторых, производительность конкретной вкладки браузера в конкретный момент времени очень сильно зависит от внешних факторов — сколько вкладок открыто, нет ли тяжёлых сайтов в других вкладках, не свёрнут ли браузер.
Было опробовано несколько теоретических и практических гипотез, из которых родилось финальное решение. Решение состоит в следующем:
- На экране загрузки игры, где идёт прогресс от 0 до 100 %, фактическая загрузка ресурсов заканчивается на 92 %.
- После этого за пределами экрана создаётся сцена, на которую помещаются тяжёлые анимации и немного физики.
- Далее в течение 5 секунд измеряется среднее время отрисовки одного кадра.
- После этого принимается решение о производительности устройства и прогресс доходит до 100 %.
Очень важным было требование полной работоспособности игры в IE 11, что тоже доставляло неудобства. Оказалось, что при запущенных инструментах разработчика, и без того небыстрое выполнение Javascript в этом браузере ещё замедлялось.
То есть ты сталкиваешься с тормозами в игре, открываешь инструменты разработчика, чтобы найти причину, а игра тормозит ещё больше.
Игровые механики
Игровые механики сами по себе несложные, во многом вдохновлённые существующими играми.
Главный герой, например, это цельный спрайт анимации вместе с оружием. Такое решение было выбрано, чтобы избежать рассинхрона анимаций замаха и оружия. Поэтому проверка нанесения урона происходит так — в момент определённых кадров анимации удара (кадра с третьего примерно) рассчитываем область пересечения, которая действует в течение ещё нескольких кадров анимации. Так нам удалось добиться реалистичности срабатывания оружия.
Обратной стороной такого решения в анимации главного персонажа стало то, что для каждого пола на каждом из уровней нужен свой отдельный набор подготовленных анимаций с оружием. А на втором уровне потребовался ещё один дополнительный набор — в кредитных кроссовках. Итого получилось по четыре полноценных набора анимаций для каждого персонажа.
Из забавного здесь ещё то, что когда выбираешь оружие для финальной битвы, то по факту выбираешь всего персонажа из соответствующего уровня. Так, все герои с мечом будут в обычных кроссовках.
Интересной была механика с ловлей ключей от сундука. Для ключа, который нужно было поймать, область срабатывания сделана меньше, чем визуальный спрайт ключа, а также незначительно смещена в сторону случайным образом. Это привело к желаемому эффекту «у меня ключ с первого раза не собирается» — иногда нужно несколько раз попробовать собрать ключ, чтобы попасть на область его срабатывания. Иначе было слишком просто, хотя в финальном релизе область срабатывания всё-таки была чуть увеличена, чтобы уменьшить процент неудачных попыток.
Все остальные механики собственно тем же и являются — срабатывание приближения и пересечения персонажа и игровых объектов в определенные моменты времени и анимации.
Чуть сложнее были механики с Драконом Страхования, перелётом через пропасть и финальной битвой. Приёмы использовались те же самые, но дополнительно были срежиссированы паузы и бездействия, для того чтобы в это время воспроизвести анимации других персонажей.
Выводы и советы
Определитесь с жанром на самом раннем этапе.
Игры в вебе — это реально существующее явление, со своей аудиторией и со своими правилами. Такие игры не требуют установки, позволяют устраивать короткие игровые сессии, механикой привлекают больше, чем внешним видом.
Совет — относитесь к разработке веб-игры как к реальной игре, а не как к очередному «скрипту на странице». Тестируйте, профилируйте, не допускайте утечек памяти и повышенной нагрузки на процессор. Игроки и батареи их устройств будут довольны.