メインコンテンツに移動
デベロッパーのためのクラウド活用方法

サーバーレスでターンベース制のネット対戦ゲームを作った話

2024-01-04 | Author : 竹内 佑介 (Pegass85)

はじめに

はじめまして、インディーゲームスタジオ Pegass85 代表の竹内佑介です。

現在、私は巨大ロボット同士の読み合いバトルゲーム、機動倶楽部Gブレイバーバースト (以下、Gブレイバーバースト) の開発しています。Gブレイバーバーストはオンライン対戦機能を実装しており、バックエンドは AWS のサーバーレスアーキテクチャを採用しています。この記事では、なぜ Gブレイバーバーストがサーバーレスアーキテクチャを採用したのか、サーバーレスを用いたネット対戦の際に発生する問題とその解決策について詳しく説明します。


X ポスト » | Facebook シェア » | はてブ »

builders.flash メールメンバー登録

builders.flash メールメンバー登録で、毎月の最新アップデート情報とともに、AWS を無料でお試しいただけるクレジットコードを受け取ることができます。 
今すぐ登録 »

Gブレイバーバーストの紹介

Gブレイバーバーストは巨大ロボで読み合いを楽しむゲームです。本作はターン制バトルながら、運任せの要素がほとんどありません。攻撃、防御のエネルギー配分を考え、ロボ、パイロットの特殊能力を使いこなし、勝利をこの手に掴みましょう。
A 3D-rendered scene from a multiplayer robot battle game, featuring two large robots facing off in a city street, each with health bars and attack values displayed above them. The environment includes modern buildings and traffic lights, highlighting a dynamic gaming interface.

サーバーレスアーキテクチャを採用した理由

Gブレイバーバーストは three.js で制作されたブラウザゲームです。このゲームにネット対戦を導入するためには、以下の要件が必要でした。

  1. WebSocket通信ができる対戦サーバー
  2. スケーラビリティ
  3. 自動デプロイ

Amazon GameLift や Photon は素晴らしいゲームサーバーですが、1 に関する情報が不足していたので採用は諦めました。その後、AWS Alien Attack: A Serverless Adventure という AWS 公式のハンズオンを発見し、サーバーレスなら 1  から 3 までの条件を満たすことがわかりました。さらに、サーバーレスはノウハウも豊富なことから、Gブレイバーバーストでのサーバーレス採用を決定しました。

アーキテクチャ

Gブレイバーバーストのアーキテクチャのポイントは、以下の通りです。

  1. Amazon S3 ホスティング + Amazon CloudFront での静的コンテンツ配信

  2. Amazon API Gateway + AWS Lambda + Amazon DynamoDB での API

  3. AWS Fargate による常時起動サーバーでのマッチメイク

  4. IDaaS としての Auth0

1 には three.js 製の Single Page Application、2 は serverless framework による WebSocket API および Rest API、3は AWS CDK で Fargate を構築しています。2、3 は GitHub にソースコードを公開しているので、興味のある方は以下から確認をお願いします。

Gブレイバーバースト バックエンド+インフラ ソースコード »

ネット対戦のキモとなる状態同期は 2 だけで実現していますが、どのように実装したのかを次のセクションで説明します。

Architecture diagram showing a serverless multiplayer game on AWS, including integration with Amazon CloudFront, Amazon S3, Amazon API Gateway, AWS Lambda, Amazon DynamoDB, Amazon Fargate, and Auth0 for user authentication. Diagram labels are in Japanese.

サーバーレスで状態同期する方法

はじめにターンベース制のゲームで状態同期するロジックを考えてみましょう。こちらが状態同期ロジックの概要図です。

  1. プレイヤーがゲームサーバーにコマンドを送信
  2. ゲームサーバーに 2 人分のコマンドが存在するかをチェック
  3. コマンドが揃っていた場合、ダメージ計算などを行いゲームを進める
  4. 3. の結果をプレイヤーに送信する
2人のプレイヤー(プレイヤーA、B)がゲームサーバーにコマンドを送信し、サーバー側でコマンドが揃ったかチェックした後、ゲームが進行し、その結果が両プレイヤーに返される流れを図式化したサーバーレス型マルチプレイヤーゲームのコマンドフローダイアグラム(日本語)。

素朴な状態同期 API

上記ロジックを素朴に実装するなら、こののような素朴な状態同期 API を作れば良さそうです。
A flowchart in Japanese depicting the process of a serverless multiplayer game, including command transmission, validation, game progression, and result distribution to all players.

同時アクセスの問題

素朴な状態同期 API は一見問題無いように見えますが、同時アクセスの問題があります。たとえば、こののように各プレイヤーの API 呼び出し時間帯が被った場合、ゲーム進行以降の処理が 2 回呼ばれることがあります。

データベースの種類によっては上記挙動とは異なる場合もありますが、同じデータに対して複数プレイヤーが同時に読み書きをしているので、いわゆる排他制御を導入する必要があります。キューを活用して一人ひとりが順番に処理実行できるようにする、テーブルに悲観ロックをかけて処理が完了するまで他プレイヤーを待たせる、などが代表的な排他制御ですが、AWS Alien Attack では別の方法が提示されていました。

サーバーレス・マルチプレイヤーゲームの正常なコマンドフローと異常なコマンドフローを比較した図です。正常系では全プレイヤーのコマンド受信でゲームが進行し、異常系ではコマンドが2回実行されるケースが示されています。日本語の解説付き。

AWS Alien Attack の状態同期方法

AWS Alien Attack は一人で遊ぶインベーダーゲームのようなものですが、他プレイヤーも含めたスコアランキングがリアルタイムで更新されるという特徴がありますが、この部分がターンベース制ゲームでの状態同期実装方法の参考になります。

 

AWS Alien Attackでは、ルームに参加しているプレイヤーの間でスコアランキングが共有されので、登場人物は以下のようになります。

  • ルーム作成者

  • ルーム参加プレイヤー


これを踏まえ、AWS Alien Attack では、こちらのようにスコアランキングのリアルタイム更新を実現しています。

ルーム作成者という代表者一人だけでスコアランキング作成 API を定期的に呼び出しす、いわゆるポーリングをしているので、素朴な状態同期 API で問題になった同時アクセス問題が解決されています。この考え方をターンベース制ゲームの状態同期に応用します。

ゲームサーバーを中心に、ルーム作成者とルーム参加プレイヤーがスコア送信やランキング取得を行うサーバーレスなマルチプレイヤーゲームのフローチャート(日本語)。ポーリングやスコアランキング作成の流れが説明されています。

Gブレイバーバーストの状態同期

AWS Alien Attack ではルーム作成者が一人だけでスコアランキング作成をポーリングすることで、同時アクセス問題を解決していました。これを Gブレイバーバーストにも応用したいのですが、同作にはルーム作成者は存在しません。なのでプレイヤーの代表者一人が、ルーム作成者も兼ねるようにしました。これより、Gブレイバーバーストのネット対戦の登場人物は以下のようになります。
 

  • 通常プレイヤー

  • ポーリング担当プレイヤー

以上を踏まえて、Gブレイバーバーストではこのように状態同期をしています。

サーバーレスで構築されたマルチプレイヤーゲームにおけるポーリング方式の通信フローを示す日本語のダイアグラム。プレイヤー間のコマンド送信、ポーリング担当プレイヤー、ゲームサーバーの関係が図式化されています。

フローチャート

ポーリング担当プレイヤーだけがコマンドチェックをすることで、素朴な状態同期API で問題になった同時アクセス問題を解決しているのがミソです。なお、ポーリング担当プレイヤーは、試合前にランダムで決められます。

図のみではポーリング担当プレイヤーのフローが分かりづらいので、こちらにフローチャートを提示します。

サーバーレス・マルチプレイヤーゲームの進行を示す日本語のフローチャートで、「開始」から「コマンド送信」「コマンドが揃ったか」「ゲーム進行」「ゲーム結果送信」「終了」までの流れが図示されています。

余談:ポーリング担当プレイヤーの割り当てが難しいケース

本節で提示したポーリング担当プレイヤーを割り当てる方法は、汎用的な状態同期方法として使えそうです。しかし、ポーリング担当プレイヤーが固定されないケース、たとえばカジュアルマッチなどロビーの入退室が頻繁に起こるようなケースでは、どのようにしてポーリング担当プレイヤーを引き継ぐのかという問題があり、この解決は並大抵ではありません。

Gブレイバーバーストではカジュアルマッチを実装していますが、マッチングが成立したプレイヤーはロビーから退出となるため、ポーリング担当プレイヤーの割り当てができません。なので常時起動サーバーとして Fargate を立ち上げて、マッチングチェックのポーリングを実行させています。

まとめ

本エントリーでは Gブレイバーバーストを題材にして、サーバーレスアーキテクチャを使用してターンベースのオンライン対戦ゲームを実現する方法について解説しました。Gブレイバーバーストでは、同時に実行できないコマンドチェックなどの処理を、代表者一人がポーリングすることで整合性を確保しています。

Gブレイバーバーストのネット対戦実装で参考にした AWS Alien Attack には、Amazon Kinesis を使用したデータ分析や Amazon Cognito を活用した権限管理など、ゲームプレイそのものとは直接関係しませんが、サービス運営に必要なノウハウが豊富に含まれています。現在の Gブレイバーバーストの規模では、これらの要件がすぐに必要なわけではありませんが、サービスが成長した暁には再度 AWS Alien Attack を勉強する予定です。

筆者プロフィール

竹内 佑介 
Pegass85

Pegass85 の代表で、IT 企業に勤務しながら「機動倶楽部Gブレイバーバースト」を開発中。 Gブレイバーバーストの原型は大学時代に作成したものであり、当時からネット対戦機能が欲しいとの声があったがスキル不足で諦めていた。 しかし、社会人になり AWS に出会い、スキルさえあればどんなサービスでも自作できることを確認。 業務で AWS の知見を得つつ、それをフィードバックして Gブレイバーバーストを完成させた。

A 3D-rendered robot mecha featuring green illuminated lights on its body, set against a black background.