ИгрыХабрахабр

Как мы сделали игру для Highload++ с воксельной графикой и VR

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

Ребята в команде Александра считают себя не просто отличными инженерами, а называют себя великой командой voxel джедаями, мастерами оптимизации, гуру 3D и повелителями больших данных! О спикере: Александр Хаёров (@allexx) руководит отделом разработки в компании Ingram Micro Cloud. [примечание: по аналогии с названиями должностей в LinkedIn и Medium]

Поэтому они запилили игру, о создании которой и пойдет дальше речь. Эта классная команда, готовясь к выступлению на Highload++ 2017, решила развлечь аудиторию и сделать что-то новое и интересное для стенда.

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

Итак, поехали!

Часто, разбирая почту, я просматриваю заголовки информационных лент, где мелькают самые разные новости. Однажды я увидел заголовок «Кто такие инди-разработчики». Почему-то он меня зацепил, и я решил почитать эту статью. Я открыл ее — там было очень много цифр, букв и статистики.

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

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

В этой статье я узнал несколько забавных фактов:

  • 97% мифических инди-разработчиков — это мужчины;
  • 60% из них — нет, не одиночки, но делают игры в одиночку;
  • В среднем, чтобы сделать инди-игру, требуется от 1 до 3 месяцев.

Так получилось, что мы тоже начали делать игру.

Почему мы начали делать игру

Мне всегда нравились игры от сервиса Reddit. Думаю, и вы не один месяц своей жизни провели на этом ресурсе.

A social experiment by Reddit

Каждый год Reddit проводит социальный эксперимент, как они это называют. Хотя на самом деле это различные игры для сообщества. В 2017 году социальный эксперимент проходил, как всегда, в начале апреля (на день дурака).

Разработчики Reddit создали картину из 1 000 х 1 000 пикселей. Суть игры была многообещающей. Каждому зарегистрированному пользователю на Reddit, а их несколько миллионов, предлагалось закрасить 1 пиксель этой канвы одним цветом из достаточно широкой палитры.

Люди создавали разные картинки, боролись между собой, перекрашивая пиксели. Мероприятие продолжалось 72 часа, и каждый участник раз в 5 минут мог нарисовать лишь одну точку на экране. Некоторые страны и сообщества объединялись и делали совместную работу.

В конечном итоге получилось интересное панно, из которого кто-то потом сделал пазл, кто-то связал носки с таким орнаментом и т.д.

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

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

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

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

The Game

Features

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

  • Однозначно хотелось сделать мультиплеер.

Мы решили, что игра будет сетевая, да еще и массовая, а не в формате разделения экрана.

  • Мы выбрали 3D-графику.

Хотя сделать 2D без опыта было бы, вероятно, проще, команда захотела объема.

  • Решили взять хайповую технологию — пусть это будет Виртуальная Реальность.

Мы понимали, что без переоценённой, передутой технологии невозможно сделать успешную игру.

Так у нас образовался Features set, но без определенного геймплея.

Concessions

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

  • Нам на самом деле не хотелось писать отдельного клиента, и мы решили, что игра будет браузерная, тем более что мы слышали, что современные браузеры стали очень мощными и позволяют делать 3D-графику.
  • Вторым важным фактором было то, что мы, являясь инженерами, конечно же стремимся к прекрасному, но к графике имеем посредственное отношение. Поэтому идея использовать маленькие воксели или блоки для того, чтобы создавать весь мир и конструкцию, нам показалась некоей панацеей.
  • Наконец, мы решили, что мир у нас не будет бесконечным (хотя я уверен, что вселенная бесконечна) и ограничились размерами 1000×1000×200 вокселей, тем самым немножко упростив для себя техническую особенность игры.

Например, в игре Minecraft мир представлен вокселями.
Справка: Воксель (Voxel) — это практически пиксель, но в 3-мерном мире.

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

Gameplay и правила

Кажется, что геймплей — это очень простая вещь! Мы прекрасно знаем, как играть в StarCraft, Doom или Quack. Но когда вы создаете свою игру, у вас возникает огромное количество идей. Эти мысли разлетаются в разные стороны и очень сложно (особенно в команде) договориться о том, как игра будет выглядеть и что в ней будет происходить.

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

  • Нужно найти спот — некое здание — именно поэтому игра называется Urban (Город).
  • На споте есть флаг, который нужно захватить, за это начисляются баллы.
  • Участник, набравший больше всех баллов, получает приз.
  • Игроки могут свободно перемещаться по общему миру и перезахватывать флаги (вариация «capture the flag»).

На этом мы определились со всеми менеджерскими функциями и решили заняться архитектурой.

Архитектура

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

  1. Игроки.
  2. Специальный стенд для того, чтобы поиграть в шлеме виртуальной реальности.
  3. Браузер, поскольку мы решили, что это будет браузерная игра. Люди будут туда приходить и получать оттуда данные.
  4. Какая-нибудь «хранилка» — ведь у нас многопользовательская игра по сети, нам нужно где-то хранить данные о разных игроках.

Это была изначальная, достаточно наивная схема архитектуры.

Проблема репликаций в распределенных системах

Как «хранилка» должна общаться с браузером, где работает игра? Тут начинаются интересные моменты, и я бы хотел вас отвести в более знакомую область.

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

Выделяются два вида репликаций:

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

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

Плюсы и минусы активной репликации:

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

Действительно, не нужно никакое дополнительное устройство в виде сервера, которое будет принимать, обрабатывать и передавать другим игрокам данные.  + Второй важный момент — эта система достаточно эффективна.

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

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

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

Плюсы и минусы пассивной репликации:

 + В отличие от активной, пассивная репликация очень стойкая к десинхронизации. Если что-то пойдет не так, есть специальное устройство — сервер, который может привести систему в норму.

Недавно появилась игра VKpixel Battle — прямой аналог игры Place от Reddit, в которой тоже можно было разрисовывать доску.  + Вторым моментом, и зачастую очень недооцененным и важным, является безопасность игр. В пассивной модели безопасность игры заметно легче обеспечить по той причине, что опять-таки есть сервер, где можно много всего контролировать. Эту игру взломали в течение нескольких часов ( источник ).

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

На самом деле сейчас подавляющее большинство игр (порядка 99%) используют пассивную репликацию. Мы недолго думали, и, как и разработчики всех современных игр, выбрали пассивный способ репликации. Поэтому на нашей мощной enterprise-архитектуре появился еще один компонент — game-бэкенд, который берет на себя задачу синхронизации.

Data Structure

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

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

Можно взять всю информацию о кубиках (вокселях) и хранить в обычном линейном большом массиве. В ней очень много вокселей и ограниченный мир. Его основным преимуществом является константная запись и чтение в ячейку. Это очень простой и понятный способ. Мы можем спокойно получить информацию о вокселе, и это потребует какое-то константное время.

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

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

Не будем вдаваться в то, что это такое, предлагаю для понимания просто посмотреть на картинку. Эту проблему можно решить, например, с помощью октодеревьев.

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

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

Это дает определенные преимущества. Наконец, есть третий вариант, я бы его назвал компромиссным — можно взять обычный линейный массив и разделить его на некоторые равномерные области (чанки). Нам не нужно загружать целый мир одного пользователя. Например, в отличие от обычного массива, можно подгружать отдельные блоки. Мы можем загружать только ближайшие от него блоки.

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

После этого выбор хранилища для нас прошел незаметно: мы решили — пускай это будет MongoDB. Мы решили, что для нашей игры последний вариант оптимален и выбрали его. Однако мы имели небольшой опыт работы с этой базой и поэтому решили на ней остановиться для экспериментов. Я бы сейчас не хотел разводить холивар на эту тему — уверен, что на многих других прекрасных базах данных это тоже можно реализовать.

Протокол взаимодействия между фронтендом и бэкендом

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

Можно проигнорировать высоту и всегда использовать максимальную высоту в выгрузке. Как мы уже знаем, наш мир представлен в виде параллелепипеда с основанием 1000×1000 и высотой 200. Это сильно упрощает создание игры.

В свою очередь каждый квадрат в соответствии с нашим стандартом мы разбили на чанки 32×32 вокселя внутри.

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

  • служебное поле id,
  • координаты,
  • название цвета игрока,
  • некое служебное название,
  • дата, когда этот блок появился.

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

  1. Определяем ближайшие чанки, которые игрок может видеть, и формируем радиус. На самом деле это не совсем корректное название. Мы формируем понимание расстояния и смотрим, какое количество чанков это затрагивает. Далее делаем запрос get к базе данных, в котором говорим текущую координату игрока и этот радиус.
  2. Создаем set — блок или кубик на карте. Здесь достаточно просто отправить координаты кубика, который хотим установить.

Это прямые запросы в наше хранилище.

В обратную сторону можно наблюдать запросы об обновлении прочих кубиков.

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

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

Так у нас сформировался протокол взаимодействия.

Мы решили остановиться на WebSocket по понятным причинам — для того, чтобы интуитивно уменьшить потенциальные задержки, которые были возможны. У нас был небольшой выбор того, как мы можем общаться между бэкендом и фронтендом: HTTP, WebSocket, HTTP2.

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

Ключевой точкой взаимодействия в нем стал WebSocket. Так у нас сформировался определенный стек в архитектуре.

Game-backend

Бэкенд, как минимум, можно назвать сердцем нашей системы.

  • Так как мы имеем определенный опыт в web-разработке, мы решили не использовать новых, для нас неизвестных технологий. Мы остановились на Python 3.6 и aiohttp. То есть у нас получился полностью асинхронный сервер.
  • К нему мы добавили измененный loop — это uvloop, который позволяет еще быстрее работать.
  • Так как мы используем MongoDB, нам нужен был какой-то асинхронный клиент. Для этого мы использовали motor, который прекрасно позволяет общаться с MongoDB в асинхронном режиме.
  • Наконец, для того, чтобы выставить наш сервер наружу, мы использовали gunicorn, который разрабатывает на Python.

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

Game-frontend

Это изюминка нашей игры — то, как игра начинает жить и существовать.

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

Эту идею мы достаточно быстро отмели, потому что по опыту в web-разработке понимали, что разрабатывать самому web-сервер — очень странная и долгая затея. Поэтому первая мысль была — использовать обычный нативный JavaScript, посмотреть, какой API предоставляет WebGL и начать делать игру. Тем более у нас не было так много времени.

На самом деле она стала для нас Граалем, потому что представляет очень много инструментов. После недолгих поисков мы нашли JS-библиотеку, которая называется Voxel.js.

В ней присутствует все, что необходимо. Библиотека существует уже более 3 лет, и, как заявляет автор, фактически является tool-kit для создания современных браузерных игр, причем воксельных.

  • Понятие мира, в котором есть оси и координаты;
  • Работа с блоками (вокселями), которые понимают концепцию чанков;
  • Инструменты для создания видеоигр:
    •  ограничивающие многогранники для того, чтобы понимать столкновения, нахождение рядом, работу с объектами и т.п.;
    •  ray casting — метод, который позволяет из 3D-объектов создавать на мониторах вид 2D;
    •  текстуры.
  • Самое главное, есть понятие игрока и его управление. Фактически мы получили уже почти готовую игру!
  • Все необходимые события — цикл создания мира, цикл установки блока и т.д. На все из них можно подписаться и производить свои действия.

Как выглядит весь стек

  • Мы пишем свой код, используя библиотеку Voxel.js — это наша специальная логика.
  • В свою очередь Voxel.js общается с библиотекой, которая называется three.js. На ней я немножко остановлюсь, потому что она является краеугольным и важным камнем во всей этой схеме.
  • Далее three.js уже общается с WebGL, которая фактически встроена в браузер (использует его API).
  • WebGL работает уже с настоящим оборудованием — с OpenGL драйвером, который рисует картинку на мониторе.

Хотя кажется, здесь нет ничего сложного ровным счетом. На самом деле сцену с использованием three.js, и в частности с Voxel.js, который это использует, произвести на свет не так уж и просто.

Посмотрим на код, но не будем заранее пугаться.

Чтобы создать классную 3D-картинку в браузере, нужны на самом деле всего 3-4 вещи:

  1. В первую очередь нужна сцена, как и в обычном мире.
  2. На этой сцене должна быть камера — мы создаем объект camera, в котором обозначаем размеры и максимальное/минимальное расстояние, которое мы видим.
  3. После этого нам нужно устройство, которое будет рендерить — создавать для камеры на сцене то, что мы хотим видеть. Для этого мы создаем render. В данном случае как раз используется WebGL технологии, и наша видеокарта будет трудиться для того, чтобы создать мир.

В принципе, у нас есть все для того, чтобы игра работала. Единственное, не хватает каких-то объектов.

Для того, чтобы создать объект, нам нужны:  4.

  • Геометрия (geometry) — это то, как объект будет выглядеть в пространстве. Например, если это куб, то у него должны быть вершины и грани.
  • Материал (material) — для того, чтобы раскрасить объект. Самый простой вариант — использовать цветную заливку.

Соединив геометрию и материал, мы получим так называемый mesh (или некую сетку объекта).

Как setInterval в браузере, она каждый раз отрисовывает новый фрейм и получается анимация. Дальше вызывается простая функция animate. Фактически этот механизм используется в обычных 3D играх и доступен в браузере.

Виртуальная реальность

Я бы хотел поговорить немножко о VR. Как я уже говорил, нам хотелось использовать хайповую передутую технологию для того, чтобы привлечь внимание. Мы решили использовать VR. Это был случайный, спонтанный выбор, но изучив тему, мы поняли, что VR — это не очень новая и не очень хайповая технология. Эта картинка датирована началом XX века — это VR, но XX века!

Нужно всего лишь использовать этот шлем, чтобы рассматривать настоящие 3D-объекты — единственное, что в статике.

Oculus Rift

Мы решили использовать не статическую картинку, а все-таки создать графику с видео. Поэтому наш выбор пал на Oculus Rift.

В нем нет ничего особенного, Oculus Rift представлен, как минимум, 3 базовыми устройствами: Опять-таки выбор был достаточно интуитивный и спонтанный.

  1. шлем;
  2. специальное устройство для того, чтобы понимать трекинг, то есть движение головы, которое носит вспомогательный характер (слева);
  3. контроллер — источник команд, который может быть представлен разными
    устройствами.

Никто из нас до этого с VR-технологиями и со шлемом Oculus не имел дела.

Плюсы:

 + Это действительно VR-картинка — она вполне настоящая и позволяет обманывать наш мозг и представлять, что мы находимся в 3D-мире.

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

Можно сказать, что это действительно потребительское устройство.  + Это действительно очень удобное устройство, хорошо сделанное, которое прекрасно лежит в руке и отлично носится на голове.

Минусы:

На самом деле это огромное количество проводов.  - Я представлял себе VR так, что можно просто надеть шлем, девайсы и будет классно! Фактически к каждому устройству необходим кабель, а то и два.

Оказалось, что есть серьезные ограничения: можно использовать только Windows, Oculus и SDK не доступен для macOS/Linux.  - Второй важный для меня момент и легкое разочарование — я ожидал, что я возьму свой обычный лэптоп и смогу программировать, сидя на диване. Возможно, это стратегия компании или особенность операционной системы — мне сказать достаточно сложно.

Я не являюсь ярым геймером современных 3D-игр и поэтому мне пришлось искать ее для того, чтобы начать разработку.  - Я не смог запустить даже простое видео или игру в VR, не подключая достаточно приличную видеокарту.

Думаю, что если вас не стесняют эти минусы, то смело можно пробовать современные шлемы виртуальной реальности.

Как делать игры для VR

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

A-Frame

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

Он является лидером и вообще доминирующим фреймворком для создания дополненной и виртуальной реальности. Наверное, первое, что можно найти в интернете, это фреймворк A-Frame.

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

Вам не придется компилировать код, не нужны специальные программы — достаточно использовать свой браузер и обычный блокнот для того, чтобы написать первую 3D VR-сцену в браузере. Но, наверное, самое здоровское то, что если вы являетесь web-разработчиком, он будет вам очень близок, потому что использует парадигму и концепцию HTML.

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

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

Так мы начали делать версию для VR.

VR здесь на самом деле находится в правом нижнем углу. Вы спросите — а где здесь VR? Там появляется очень маленький значок очков виртуальной реальности. На этой картинке этого нет. Это выглядит абсолютной магией, потому что вы не делаете ничего специально для того, чтобы появилась виртуальная реальность. При нажатии на эту кнопку, появляется VR-картинка. Это делает за вас фреймворк.

Для этого достаточно создать изображение для двух глаз и правильно его расположить. Если посмотреть детальнее, то здесь нет ничего сложного. Это позволит генерировать правильную картинку.

Возвращаясь к нашей enterprise-архитектуре, мы пришли к тому, что у нас будет два клиента:

  1. Один для обычной игры с использованием Voxel.js.
  2. Другой — с использованием библиотеки A-Frame.

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

Оптимизация

Напоследок хотел бы рассказать немного об оптимизации.

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

Pre-process voxel models  1.

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

Первое, что нам пришло на ум: «Почему бы не сделать объекты полыми, то есть внутри не создавать эти самые кубики? Когда этот мир загружался, наша картинка требовала много данных и достаточно медленно работала, поскольку содержала очень много вокселей. Ведь пользователь их все равно не увидит!»

Это просто колоссально снизило количество передаваемых данных — примерно на 78% уменьшило количество вокселей в мире. Мы написали очень простой алгоритм, который позволяет исключать из нашего мира, который мы создали в отдельном редакторе, воксели, которые находятся внутри.

User Mesher2.

Дело в том, что, создавая игру с воксельной графикой, мы конечно же в голове у себя представляем отдельные кубики. Вторым важным моментом является рекомендация использовать mesher. Но в действительности мир, как и в Minecraft в том числе, устроен немножко по-другому.

Для этого используется специальный инструмент mesher. Мы используем обычные полигональные модели, и поэтому имеет большой смысл все отдельные воксели соединять вместе в сеть (или Mesh). Для того, чтобы просчитать, например, падение света или какую-то физику, нужно меньше вычислительных ресурсов, поскольку будет меньше полигонов. Он колоссально увеличивает производительность, потому что уменьшает количество вершин, граней, ребер.

Так c Voxel.js мы получили достаточно приличный FPC изначально. Кстати, в некоторых фреймворках mesher включен по умолчанию. В A-Frame такого нет, и мы использовали mesher уже дополнительно.

Enable compression for WebSocket (RFC 7692)3.

WebSocket — отличная технология, но по умолчанию она не производит никаких манипуляций с теми сообщениями, которые передаются с ее помощью. Наконец, оптимизация из мира web-разработки.

Эти данные были очень похожи друг на друга. Мы передавали достаточно большое количество текста (в данном случае JSON) между клиентом и сервером. Поэтому у нас возникла идея — почему бы нам их не сжать?

Открытием для нас, возможно, это будет также приятным открытием для вас, стало существование специального RFC, который описывает, как можно делать компрессию внутри WebSocket. Единственной загвоздкой было наличие WebSocket, а не классического HTTP.

Фактически включение такой технологии на сервере в нашем случае позволило заметно понизить трафик — буквально с 5 MB передаваемых данных до 1,8 MB. Там есть несколько технологий, основанных на использовании специальных плагинов.

Вам достаточно правильно включить компрессию на сервере и реализовать ее, и все будет прекрасно работать. Приятно, что современные браузеры — такие, как Chrome, Firefox, Safari — поддерживают компрессию со стороны клиента.

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

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

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

Кстати, к РИТ++ 2018 ребята готовят ремейк логической игры Pipes — называется CloudPipes.

Что еще раз подтверждает тезис, участие в конференциях, особенно наших, — это весело!

Где? Расписание фестиваля с докладами, митапами, викториной и «Что? Когда?» готово, а у вас еще есть шанс приобрести билет.

Также на забывайте про Highload++ Siberia, которая тоже всего через месяц.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»