非同期マルチプレイヤーのリファレンス アーキテクチャ
非同期マルチプレイヤーを構築するためのバックボーンは、ゲームの状態を永続データベースに保存してゲーム セッション内のすべてのプレイヤーが次のターンになったときに取得できるようにすることと、プッシュ通知 メカニズムです。
非同期マルチプレイヤーを定義する際には、考慮できる変数がいくつかあります。
- 並列する複数のゲームのサポート - あり/なし。
- 期限 - ターンを完了するかゲームが失効するまでのプレイヤーの持ち時間 (6 時間、12 時間、24 時間など)。
- ゲームのカスタム設定 - プレイヤーがゲームの特定の設定を使用して新しいゲーム セッションを作成できるようにするかどうかを検討します。
参照実装の詳細
この特定のリファレンス アーキテクチャでは、サーバーレスのシンプルな三目並べゲームを示します。 次に示すのは、同じユース ケースをさらに簡単に始めるための別の実装です。
- サーバーレス - Azure Functions を使用します。
以下のセクションでは、記載されているさまざまな実装に共通する一般的な設計上の考慮事項について説明します。
プレイヤー認証と ID
このリファレンス アーキテクチャでは、プレイヤー認証と詳細なプレイヤー ID 管理は扱いません。これらについては各自で調べてみてください。
PlayFab には複数の認証形式が用意されているため、複数のデバイスにわたってプレイヤーを追跡できます。
- ゲスト ログイン用のデバイス ID
- ユーザー名/パスワード
- Google アカウント
- GameCenter アカウント
- Facebook アカウント
- Steam アカウント
- Kongregate アカウント
- Twitch アカウント
- その他の oAuth プロバイダー
- Android デバイス ID
- カスタム プレイヤー ID
複数のデータ センターへの拡張
このリファレンス アーキテクチャでは、バックエンドに対して 1 つのリージョンのみを想定しています。 構築するゲームによっては、トラフィック マネージャーの利用と複数のデータ センターへのデプロイが不要な場合があります。 Traffic Manager は HTTP 呼び出しに使用されるため、すべてのリソースが 1 つのデータ センターにあり、世界中に分散されていない場合、コストをより低く抑えられる可能性があります。 さらに、複数のデータ センターを使用することは、データベース同期メカニズムを使用して異なるデータ センター間でデータベース データを同期する必要があることも意味します。 それでも複数のデータ センターを使用したい場合は、Traffic Manager を使用する必要があります。
ステップ バイ ステップの手順
非同期マルチプレイヤー タイトルの一般的なフローは次のとおりです。
- プレイヤーがバックエンドにログインします。
- 既存のプレイヤーのゲーム リストがバックエンドから取得されます。
- プレイヤーが一連の設定を使用して新しいオープン状態のゲームを作成するか、特定の対戦相手を招待します。
- プレイヤーが新しいオープン状態のゲームを作成した場合は、ゲーム セッション リストに追加され、対戦相手の参加を待機します。 プレイヤーが新しいオープン状態のゲームを作成するときは、実際には対戦相手への接続要求を送信しています。 設定と一致する、他の適切な待機中のプレイヤーがいる場合は、ゲームが両方のプレイヤーを直接マッチメイキングします。
- プレイヤーが別の特定のプレイヤーを招待する場合は、新しいオープン状態のゲームを作成するが、特定の対戦相手を指定するようなものです。 このリファレンス アーキテクチャでは、この機能は検討しません。
- プレイヤーがゲームでサポートされているアクションを選択し、そのアクションがターンを実行するために送信されます。
- ターンが送信されると、このゲーム セッションの永続データベースのレコードが、更新されたゲームの状態で更新されます。
- 対戦相手のプレイヤーに通知が送信され、対戦相手が自分のターンを開始できます。
データベース スキーマ
必要な情報の格納に使用される Azure Database for MySQL 永続データベースには、3 つのテーブルがあります。プレイヤーごとに 1 つのエントリを含み、堅牢なプレイヤー ID システムに拡張する必要がある player テーブル、ゲーム セッションごとに 1 つのエントリを含む gamesession テーブル、ゲームごとユーザーごとに 1 つのエントリを含む gamesession_player テーブルです。
player テーブル
フィールド | 型 | 注記 |
---|---|---|
ID | SERIAL PRIMARY KEY | このテーブルの主キー |
CreatedTime | TIMESTAMP NOT NULL | プレイヤーが追加された時刻を格納します |
UpdatedTime | TIMESTAMP NOT NULL | プレイヤーが更新された時刻を格納します |
Name | VARCHAR(100) | プレイヤーの名前を格納します |
gamesession テーブル
フィールド | 型 | 注記 |
---|---|---|
ID | SERIAL PRIMARY KEY | このテーブルの主キー |
GUID | VARCHAR(36) | ゲーム セッションの一意の識別子 |
CreatedTime | TIMESTAMP NOT NULL | ゲーム セッションが作成された時刻を格納します |
UpdatedTime | TIMESTAMP NOT NULL | ゲーム セッションが更新された時刻を格納します |
CreatedPlayer_ID | BIGINT UNSIGNED NOT NULL | ゲーム セッションを作成したプレイヤー |
GameStatus | TINYINT NOT NULL | マッチメイキング中 (0)、進行中 (1)、または完了 (2) |
BoardState | VARCHAR(200) NOT NULL | シリアル化されたボード情報 (X と O がボードに配置される) |
MovesLeft | TINYINT NOT NULL | ゲームが終了するタイミングを判断するために使用されます |
CurrentTurnPlayer_ID | BIGINT UNSIGNED | 行動を起こす必要があるプレイヤー |
WinningPlayer_ID | BIGINT UNSIGNED | 勝ったプレイヤー |
CreatedPlayer_ID | FOREIGN KEY | player(ID) を参照します |
CurrentTurnPlayer_ID | FOREIGN KEY | player(ID) を参照します |
WinningPlayer_ID | FOREIGN KEY | player(ID) を参照します |
gamesession_player テーブル
フィールド | 型 | 注記 |
---|---|---|
ID | SERIAL PRIMARY KEY | このテーブルの主キー |
CreatedTime | TIMESTAMP NOT NULL | プレイヤーが追加された時刻を格納します |
UpdatedTime | TIMESTAMP NOT NULL | プレイヤーが更新された時刻を格納します |
GameSession_ID | BIGINT UNSIGNED NOT NULL | 外部キー。 これは gamesession テーブルからの一意のゲーム識別子です |
Player_ID | BIGINT UNSIGNED NOT NULL | 外部キー。 これは player テーブルからの一意のプレイヤー識別子です |
GameSession_ID | FOREIGN KEY | gamesession(ID) を参照します |
Player_ID | FOREIGN KEY | player(ID) を参照します |
データベース テーブルの作成
データベース接続情報を取得し、ファイアウォールを構成して、次のいずれかの手段でデータベースへの接続を確立する方法については、このチュートリアルを参照してください。
- Azure portal Cloud Shell から mysql コマンド ライン ツールを使用する (クラウド ドライブ アカウントが必要です)。
- MySQL Workbench GUI ツールを使用する。
その後、次のコマンドを実行してデータベースを作成します。
CREATE DATABASE asyncmpdb;
次のコマンドでその使用を開始します。
USE asyncmpdb;
次のコマンドで 3 つのテーブルを作成します。
CREATE TABLE player (
ID SERIAL PRIMARY KEY,
CreatedTime TIMESTAMP NOT NULL,
UpdatedTime TIMESTAMP NOT NULL,
Name VARCHAR(100) NOT NULL
);
CREATE TABLE gamesession (
ID SERIAL PRIMARY KEY,
GUID VARCHAR(36) NOT NULL,
CreatedTime TIMESTAMP NOT NULL,
UpdatedTime TIMESTAMP NOT NULL,
CreatedPlayer_ID BIGINT UNSIGNED NOT NULL,
GameStatus TINYINT NOT NULL,
BoardState VARCHAR(200) NOT NULL,
MovesLeft TINYINT NOT NULL,
CurrentTurnPlayer_ID BIGINT UNSIGNED,
WinningPlayer_ID BIGINT UNSIGNED,
FOREIGN KEY(CreatedPlayer_ID) REFERENCES player(ID),
FOREIGN KEY(CurrentTurnPlayer_ID) REFERENCES player(ID),
FOREIGN KEY(WinningPlayer_ID) REFERENCES player(ID)
);
CREATE TABLE gamesession_player (
ID SERIAL PRIMARY KEY,
CreatedTime TIMESTAMP NOT NULL,
UpdatedTime TIMESTAMP NOT NULL,
GameSession_ID BIGINT UNSIGNED NOT NULL,
Player_ID BIGINT UNSIGNED NOT NULL,
FOREIGN KEY(GameSession_ID) REFERENCES gamesession(ID),
FOREIGN KEY(Player_ID) REFERENCES player(ID)
);
次のコマンドを使用して、3 つのテーブルが作成されたことを確認します。
show tables;
テーブルが作成されたら、一連のストアド プロシージャを作成しましょう。
以下は新しいゲーム セッションを作成するためのものであり、マッチメイキングの試行で適切なゲーム セッションが返されなかった場合に実行されます。
DELIMITER //
CREATE PROCEDURE `gamesession_INSERT`
(IN param_guid VARCHAR(36),
IN param_createdplayer_id BIGINT UNSIGNED,
IN param_status TINYINT,
IN param_boardstate VARCHAR(200),
IN param_movesleft TINYINT,
IN param_currentturnplayer_id BIGINT UNSIGNED,
IN param_winningplayer_id BIGINT UNSIGNED)
BEGIN
INSERT INTO gamesession
(GUID,
CreatedTime,
UpdatedTime,
CreatedPlayer_ID,
GameStatus,
BoardState,
MovesLeft)
VALUES
(param_guid,
NOW(),
NOW(),
param_createdplayer_id,
param_status,
param_boardstate,
param_movesleft);
INSERT INTO gamesession_player
(CreatedTime,
UpdatedTime,
GameSession_ID,
Player_ID)
VALUES
(NOW(),
NOW(),
LAST_INSERT_ID(),
param_createdplayer_id);
END //
通知サービス
通知の送信には主に 2 つのサービスを利用できます。Notification Hubs と、SignalR です。 下の表は、これらの 2 つのサービスの主な違いを示しています。 この実装は、最初に SignalR 通知が試行され、一定の短い期間が経過しても受信済み通知が届かなかった場合は SignalR の送信がキャンセルされ、Azure Notification Hub がフォールバックとして使用されるというカスケード パターンに従います。
SignalR | Notification Hubs | |
---|---|---|
メッセージのソース | シナリオに応じて、ゲーム サーバー (配信またはサーバー プッシュのみ) または別のクライアント (チャットのような双方向) をソースとして使用できます | プラットフォーム プロバイダーの既存のインフラストラクチャ (Microsoft、Google、Apple など) |
専用サーバーが必要 | シナリオによって異なります。 このサービスは REST API をサポートしているため、メッセージ ソース/アプリはサーバーを必要とせずに直接 SignalR Service REST API を介してクライアントにメッセージを公開できます。 または、Azure Functions の SignalR Service とのバインドも公式にサポートしているため、サーバーレスのシナリオにも対応します | × |
コードに依存しない | はい。 SignalR は C#、JS のクライアント SDK を含むようになり、Xamarin、Unity、Java SDK にも対応します。 C++ および Object-C/Swift 向けのリリースも予定されています。 REST API はすべての REST 対応言語をサポートしています。 Azure Functions のバインドは、Azure Function でサポートされるすべての言語をサポートします | はい。REST API とテンプレートを使用できます。 |
メッセージの配信 | 即時 (WebSocket 経由) | 即時性は保証されません |