В далёком 1996 году вышла 2d аркада Mine Bombers: www.youtube.com/watch?v=iOHmVR0LINU

Я помню как мы играли в нее вчетвером на одной клаве часами напролёт. Мультиплеер режим был только типа hotseat, сетевого не было.

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

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

Архитектура сервера


В качестве основного протокола взаимодействия я выбрал вебсокеты.

На момент создания игры у меня уже был опыт использования python фреймворка Twisted, потому выбор пал на него.
Так сложилось, что с тредами я никогда дальше матчасти не углублялся, асинхронная однотредовая модель мне всегда больше импонировала (первое знакомство было с ней в далеком 2003 году — это была Perl библиотека POE ).

Для реализации клиент-серверного взаимодействия я выбрал библиотеку Autobahn, которая имеет реализацию как для python — в виде модуля Twisted AutobahnPython, так и для java (см Клиент).

Redis выполняет две роли:
  • хранилище контента и данных игроков
  • передача сообщений между процессами через pubsub (Более подробно ниже )




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

Broadcast Server — twisted процесс, который обрабатывает очередь игроков, инициирует создание игровой сессии и рассылает дальнейшие снэпшоты игрового мира, генерируемые воркерами.

Worker — twisted процесс, который генерирует игровую сцену(мир), принимая и обрабатывая действия(экшены) игроков и отправляя снэпшоты BroadcastServer'у.

Broadcast Server и Worker общаются между собой через Redis, используя шаблон обмена сообщениями publish-subscribe. Для реализации их взаимодействия была выбрана библиотека txredisapi. Она позволяет выполнять асинхронные запросы к Redis и реализована в виде twisted модуля.

У каждого BroadcastServer'a может быть несколько воркеров (хотя на диаграмме у каждого их по два — их может быть разное количество).

Registrar — это веб-сервер, регистрирующий игроков, создающий игровые сессии, выполняющий роль фронтенда к игровым данным. Для его реализации я выбрал микро-фреймворк Flask.

Общение между игровым клиентом осуществляется по защищенному протоколу HTTPS.

Registrar Redis (RR) — это отдельный Redis сервер, хранилище контента: параметры итемов, уровни, статистика игроков. В нём также хранятся сессии игроков, созданные серверами BroadcastServer.

Клиент


Идея создать игру возникла в частности из давнего интереса к android платформе. Потому проблемы выбора платформы даже и не было как таковой.

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

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

Про libgdx достаточно много писали на Хабре и не только, поэтому здесь я не буду касаться описанием ее API. Все тонкие моменты достаточно быстро решаются на их irc канале (если нет проблем с английским).

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

В качестве формата сообщений используется JSON. Для уменьшения размера пакетов, снэпшоты, как самые объемные сообщения, сжимаются gzip'ом.

Игровой процесс




При запуске игры, клиент отправляет запрос авторизации «AUTH» на сервер Registrar и в случае успешной авторизации создается сессия в RR. Он также получает список адресов серверов (BroadcastServer) и некоторый игровой контент (рейтинг, и др настройки игры).

Далее игрок выбирает сервер из списка:

Скриншот



И тип игры, всего их 4:

Скриншот



Если девайс с маленьким экраном, то лучше играть на маленькой карте (на большой будет очень мелко). Я не стал реализовывать zoom камеры, так как сам геймплей подразумевает слежение за всеми игроками на игровом поле, а при увеличении они бы пропадали из вида. Ну и из соображений экономии пространства на экране.

Выбрав тип игры, клиент отправляет запрос выбранному серверу BroadcastServer на подключение к очереди игроков «JOIN», он в свою очередь валидирует сессию игрока в RR и если сессия существует — добавляет его в очередь игроков.

BroadcastServer периодично обрабатывает очередь игроков и создает игровые сессии, отправляя запрос «CREATE GAME» выбранному воркер процессу. Воркер процесс создает игровую сессию и отправляет результат в виде сообщения «GAME CREATED». BroadcastServer рассылает его ответ игрокам.

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

Скриншот



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

После последнего раунда воркер отправляет сообщение «GAME OVER» с результатами игры и BroadcastServer бродкастит его игрокам, обновляя также статистику в RR.

Нововведения


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

Одно из нововведений, которое я добавил — это бонус уровни, лабиринты с золотом, они без мобов, что делает процесс сбора золота более простым и спокойным, своего рода брэйк. Каждый 5-й уровень в игре — бонусный.

Скриншот бонусного уровня



Ещё несколько скриншотов










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

Outro


Дабы не нарушать правила Хабра, название игры и ссылка на неё нигде не фигурирует, могу прислать через лс, название игры изменено и не похоже на оригинальное.

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

Комментарии (0)