マッチメイキングを Unity ゲームクライアントに統合する
注釈:本資料はAI技術を用いて翻訳されています。
このガイドでは、Unityゲームでのマッチメイキングの設定について説明します。Unreal Engineを使用している場合は、Unrealマッチメイキング統合ガイドを参照してください。
概要
マッチメイキングは、2人以上のプレイヤーがマッチのために評価され、一緒にプレイできるようにゲームセッションに参加するプロセスです。マッチメイキングプロセス中にAccelByte Gaming Services(AGS)マッチメイキングが相互作用するいくつかのコンポーネントがあります。
-
Session Template: セッションが作成される際の特性を定義します。これには、参加可能性、使用するゲームサーバーデプロイメント、プレイヤー要件、チーム構成などが含まれます。
-
Match Ticket: ソロプレイヤーまたはパーティによるマッチメイキングのリクエストを定義し、評価用にプレイヤー情報が添付されます。
-
Backfill Ticket: マッチチケットと似ていますが、マッチルールセットで自動バックフィルが有効になっている場合にのみ作成されます。この場合、2人以上のプレイヤーがマッチングされると、彼らはセッションに参加し、最小プレイヤー数がセッションに接続するまでマッチを見つけ続けるためにバックフィルチケットがAGSマッチメイキングに送信されます。
-
Match Pool: 有効なマッチのためにサービスによって評価できるマッチチケットのコレクションを定義します。チケットは、選択されたゲームモードと設定(該当する場合)に基づいて同じプールに入ります。
-
Match Ruleset: チケットが有効なマッチを構成するかどうかを判断するためにデフォルトのマッチ関数によって使用される属性と比較基準を定義します。マッチ関数がオーバーライドされている場合でも、評価に必要なAGS Statisticsに保存されている属性でルールセットを設定する必要があります。
-
Match Function: サービスがマッチチケットを評価するために使用するロジックを定義します。デフォルトでは、サービスは関連するマッチルールセットで定義された基準を使用します。
この記事では、Unity SDKプラグインを使用して、AGSマッチメイキングをUnityゲームクライアントに統合する方法を説明します。
目標
この記事は、マッチメイキングプレイヤー体験フローの理解を提供し、以下の統合方法を示すことを目的としています:
- ソロプレイヤーとパーティのマッチメイキングの開始
- マッチが見つかる前のマッチメイキングのキャンセル
- マッチ結果のリスニングと処理
- ゲームセッション招待のリスニングとセッションへの参加
前提条件
この記事のすべての手順を完了するには、以下が必要です:
- AGS Lobby、Session、Matchmakingに関する知識
- Unityの基本的な理解
- Unityプロジェクトにインストールされ、必要なクライアントIDを使用して設定されたAGS Game SDK
- AGS Admin Portalへのアクセス
- 作成および設定されたセッションテンプレート、マッチルールセット、マッチプール
- AGSバックエンドで認証され、AGS Lobbyに接続されたユーザーを持つゲームクライアント
マッチメイキングフローの実装
実装は、マッチメイキングフローの概要で説明されている高レベルのフローに従います。
マッチメイキング関連の通知をリスニングする
マッチメイキングフローを進める前に、プレイヤーがログインして認証されていることを確認してください。できるだけ早くLobbyサービスに接続することを強くお勧めします。
マッチメイキング関連の通知をリスニングする
// ユーザーが正常にログインまたは認証されたらすぐにLobbyサービスに接続します。
// これにより、イベントとの競合状態を回避し、正確なCCUメトリクス追跡が可能になります。
// lobby.Connect()を使用して接続を確立します。
var lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
// マッチ開始通知。
// これは、ユーザーがパーティの一部であり、
// パーティリーダーがマッチメイキングを正常に開始した場合にのみ受信されます(MatchmakingV2.CreateMatchmakingTicket)。
lobby.MatchmakingV2MatchmakingStarted += result =>
{
if (result.IsError)
{
// MatchmakingV2MatchmakingStartedが失敗した場合の処理
Debug.Log($"Error MatchmakingV2MatchmakingStarted, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// MatchmakingV2MatchmakingStartedが正常に受信された場合の処理
};
// マッチ発見通知。
// これは、パーティのマッチが見つかったときに受信されます。
// 通常、利用可能なサーバーがない場合に受信されます。これは、
// すでにマッチがあり、ゲームセッションを収容するためにスピンアップされたDSを待つことを通知するために受信されます。
lobby.MatchmakingV2MatchFound += result =>
{
if (result.IsError)
{
// MatchmakingV2MatchFoundが失敗した場合の処理
Debug.Log($"Error MatchmakingV2MatchFound, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// MatchmakingV2MatchFoundが正常に受信された場合の処理
};
// セッション招待通知。
// これは、ゲームセッションを収容する準備ができたDSがある場合に受信されます。
// ユーザーがこの通知を受信したら、ゲームセッションに参加(Session.JoinGameSession)しても安全です。
lobby.SessionV2InvitedUserToGameSession += result =>
{
if (result.IsError)
{
// SessionV2InvitedUserToGameSessionが失敗した場合の処理
Debug.Log($"Error MatchmakingV2MatchFound, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// SessionV2InvitedUserToGameSessionが正常に受信された場合の処理
};
// マッチタイムアウト通知。
// これは、ユーザーまたはパーティのマッチメイキング時間が設定されたタイムアウト値に達したときに受信されます。
// マッチメイキングプロセスを再開する前に、期限切れのチケットがすでにクリーンアップされていることを確認してください
// (MatchmakingV2.DeleteMatchmakingTicket)。
lobby.MatchmakingV2TicketExpired += result =>
{
if (result.IsError)
{
// MatchmakingV2TicketExpiredが失敗した場合の処理
Debug.Log($"Error MatchmakingV2TicketExpired, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// MatchmakingV2TicketExpiredが正常に受信された場合の処理
};
マッチメイキングを開始する
var matchmaking = AccelByteSDK.GetClientRegistry().GetApi().GetMatchmakingV2();
// マッチメイキングを開始
string matchPool = "a-match-pool";
string matchTicketId = "";
matchmaking.CreateMatchmakingTicket(matchPool, result =>
{
if (result.IsError)
{
// CreateMatchmakingTicketが失敗した場合の処理
Debug.Log($"Error CreateMatchmakingTicket, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// CreateMatchmakingTicketが成功した場合の処理
matchTicketId = result.Value.matchTicketId;
});
過去のゲームセッションを記録する
プレイヤーの過去のゲームセッションを自動的に記録する次の機能を有効にできます。有効にすると、プレイヤーの過去のゲームセッションのIDがパーティセッションストレージに自動的に同期されます。パーティメンバーは、過去のセッション情報を予約されたパーティセッションストレージに保存します。デフォルトでは、この機能は5つのセッションIDを保存します。
var matchWrapper = AccelByteSDK.GetClientRegistry().GetApi().GetMatchmakingV2();
matchWrapper.PartyMemberPastSessionRecordSyncEnabled = true;
ローカルにキャッシュされたセッションIDを変更するには、AccelBytePastSessionRecordManagerを使用できます。
var pastSessionRecordManger = AccelByteSDK.GetClientRegistry().GetPastSessionRecordManager();
pastSessionRecordManger.MaxStoredSessionIdCount = 10; //デフォルト値は5
// ローカルにキャッシュされたセッションIDの変更
// ローカルキャッシュにセッションIDを挿入
pastSessionRecordManger.InsertPastSessionId("user-id", "session-id");
// ローカルキャッシュからセッションIDを削除
pastSessionRecordManger.RemoveSpecificCachedPastSessionIds("user-id", "session-id");
// ローカルキャッシュをリセット
pastSessionRecordManger.ResetCachedPastSessionIds("user-id");
pastSessionRecordManger.ResetAllCachedPastSessionIds();
パーティメンバーが別のユーザーIDを保存する場合、それはローカルにのみ記録され、パーティセッションストレージには記録されません。これは、記録が一時的であり、プレイヤーのデバイスメモリに保存されることを意味します。ゲームが閉じられると、記録はリセットされます。
マッチメイキングを開始するための追加パラメータ
- カスタム属性: マッチメイキングに必要なカスタム属性を設定します。マッチメイキングサービスは属性をマッチングしようとします。
- サーバーレイテンシ: レイテンシは、利用可能なすべてのサーバーリージョンに対するゲームクライアントのレイテンシに関する詳細情報をマッチメイキングサービスに提供するために使用されます。指定されたリージョンにのみマッチメイキングします。すべてのレイテンシを取得するには、
QosManager.GetAllServerLatenciesを使用します。 - パーティセッションID: マッチメイキングがパーティリーダーによって実行される場合、これにパーティセッションIDを入力します。これにより、すべてのパーティメンバーがマッチメイキングに含まれ、マッチが見つかったときに通知されます。パーティセッションIDは
Session.GetUserParties経由で取得できます。 - 過去のセッションID除外: 望ましくない特定のゲームセッション(例:以前にプレイした過去のセッション)へのマッチメイキングを避けるために、次のパラメータを使用してマッチメイキング結果からそれらのゲームセッションを除外できます:
ExclusionType.AllMemberCachedSession: 記録されたすべての過去のゲームセッションを除外します。これにより、パーティリーダーは各パーティメンバーの過去のセッションを収集して1つの完全なリストにコンパイルできます。このリストは、パーティリーダーがマッチチケットを作成するときに除外されるすべてのセッションを指示します。パーティリーダーはリストを使用するかどうかを選択できます。ExclusionType.NPastSession: 記録された過去のゲームセッションの特定の数を除外します。各パーティメンバーに対して除外したい過去のセッションの数を示すために、ExcludedPastSessionCountパラメータを定義する必要があります。ExclusionType.ExplicitList: 特定のゲームセッションを除外します。除外するゲームセッションIDのリストを示すために、ExcludedGameSessionIdsパラメータを定義する必要があります。
パーティでAllMemberCachedSessionとNPastSession除外タイプを使用するには、次の点に注意してください:
- パーティメンバーはパーティメンバーの過去のゲームセッション記録の自動同期を有効にする必要があります。
- パーティリーダーは、マッチチケットを作成する前に、すべてのメンバーが過去のセッションID情報の更新を完了していることを確認する必要があります。
string matchPool = "a-match-pool";
var optionalParams = new MatchmakingV2CreateTicketRequestOptionalParams()
{
// マッチメイキングに必要なカスタム属性を設定します。マッチメイキングは属性をマッチングしようとします。
// この例では、指定されたマップのみにマッチメイキングするためのカスタムパラメータの値としてマップ名を使用します。
attributes = new Dictionary<string, object>()
{
{ "map_names", "map_01" }
},
// レイテンシは、利用可能なすべてのサーバーリージョンに対するゲームクライアントのレイテンシに関する詳細情報をマッチメイキングサービスに提供するために使用されます。
// 指定されたリージョンにのみマッチメイキングします。
// すべてのレイテンシを取得するには、QosManager.GetAllServerLatenciesを使用します。
latencies = new Dictionary<string, int>()
{
{"ap", 100},
{"eu", 90}
},
// マッチメイキングがパーティリーダーによって実行される場合、これにパーティセッションIDを入力します。
// これにより、パーティ内のすべてのユーザーがマッチメイキングに含まれ、マッチが見つかったときに通知されます。
// パーティセッションIDはSession.GetUserParties経由で取得できます
sessionId = "party-session-id",
ExclusionType = MatchmakingV2ExclusionType.AllMemberCachedSession,
// n個の過去のセッションを除外したい場合
// ExclusionType = MatchmakingV2ExclusionType.NPastSession,
// ExcludedPastSessionCount = 3,
// セッションIDを明示的に除外したい場合
// ExclusionType = MatchmakingV2ExclusionType.ExplicitList,
// ExcludedGameSessionIds = new string[]
// {
// "sessionId-to-exclude-1",
// "sessionId-to-exclude-2",
// "sessionId-to-exclude-3"
// }
sessionId = "party-session-id",
ExclusionType = MatchmakingV2ExclusionType.AllMemberCachedSession,
// n個の過去のセッションを除外したい場合
// ExclusionType = MatchmakingV2ExclusionType.NPastSession,
// ExcludedPastSessionCount = 3,
// セッションIDを明示的に除外したい場合
// ExclusionType = MatchmakingV2ExclusionType.ExplicitList,
// ExcludedGameSessionIds = new string[]
// {
// "sessionId-to-exclude-1",
// "sessionId-to-exclude-2",
// "sessionId-to-exclude-3"
// }
};
string matchTicketId = "";
var matchmaking = AccelByteSDK.GetClientRegistry().GetApi().GetMatchmakingV2();
var matchmaking = AccelByteSDK.GetClientRegistry().GetApi().GetMatchmakingV2();
matchmaking.CreateMatchmakingTicket(matchPool, optionalParams, result =>
{
if (result.IsError)
{
// CreateMatchmakingTicketが失敗した場合の処理
Debug.Log($"Error CreateMatchmakingTicket, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// CreateMatchmakingTicketが成功した場合の処理
matchTicketId = result.Value.matchTicketId;
});
ゲームセッションに参加する
マッチメイキングが完了すると、ゲームクライアントはゲームセッション招待を受信し、マッチングされたゲームセッションに参加できます。
var session = AccelByteSDK.GetClientRegistry().GetApi().GetSession();
var lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
Result<SessionV2GameInvitationNotification> InvitedToGameSessionNotif;
lobby.SessionV2InvitedUserToGameSession += result =>
{
InvitedToGameSessionNotif = result;
if (result.IsError)
{
// SessionV2InvitedUserToGameSessionが失敗した場合の処理
Debug.Log($"Error SessionV2InvitedUserToGameSession, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
Debug.Log($"Invited to game session {InvitedToGameSessionNotif.Value.sessionId}");
// ここで、ゲームクライアントはゲームセッションに参加するかどうかを決定できます
session.JoinGameSession(InvitedToGameSessionNotif.Value.sessionId, joinGameSessionResult =>
{
if (result.IsError)
{
// JoinGameSessionが失敗した場合の処理
Debug.Log($"Error JoinGameSession, Error Code: {joinGameSessionResult.Error.Code} Error Message: {joinGameSessionResult.Error.Message}");
return;
}
Debug.Log($"Successfully joined a game session {joinGameSessionResult.Value.id}");
if (joinGameSessionResult.Value.dsInformation.status == SessionV2DsStatus.AVAILABLE)
{
string serverIP = joinGameSessionResult.Value.dsInformation.server.ip;
Debug.Log($"DS Ready, IP: {serverIP}");
}
});
};
専用サーバーに接続する
ゲームクライアントは、DSが準備できているかどうかを確認するために、専用サーバー(DS)更新通知をリスニングする必要があります。または、ゲームクライアントはゲームセッションに参加した後にDS情報を確認することもできます。
var lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
lobby.SessionV2DsStatusChanged += result =>
{
if (result.IsError)
{
// SessionV2DsStatusChangedが失敗した場合の処理
Debug.Log($"Error SessionV2DsStatusChanged, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
var status = result.Value.session.dsInformation.status;
if (status == SessionV2DsStatus.AVAILABLE)
{
string serverIP = result.Value.session.dsInformation.server.ip;
Debug.Log($"DS Ready, IP: {serverIP}");
}
};
マッチメイキングをキャンセルする
プロセスが完了またはタイムアウトする前にマッチメイキングをキャンセルする必要がある場合、次のAPIを呼び出すことができます:
var matchmaking = AccelByteSDK.GetClientRegistry().GetApi().GetMatchmakingV2();
// マッチメイキング開始結果から取得
string matchTicketId = "match-ticket-id";
matchmaking.DeleteMatchmakingTicket(matchTicketId, result =>
{
if (result.IsError)
{
// DeleteMatchmakingTicketが失敗した場合の処理
Debug.Log($"Error DeleteMatchmakingTicket, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// DeleteMatchmakingTicketが成功した場合の処理
});
問題のトラブルシューティング
このセクションでは、サービスを使用する際に発生する可能性のある一般的なエラーと問題、およびそれらを解決する方法に関する推奨事項を見つけることができます。
AGS LobbyからのOnMatchmakingTicketExpired通知
AGS LobbyからOnMatchmakingTicketExpired通知を受信した場合、チケットがタイムアウト制限に達し、プレイヤーがマッチメイキングから削除されたことを意味します。これは、マッチプール設定で定義されたタイムアウトが短すぎる場合、またはマッチルールセットがプレイヤーが他のプレイヤーとマッチングできるように十分なルールフレキシングを許可していない場合によく発生します。解決するには:
- マッチプール設定を確認して、マッチまたはバックフィルチケットのタイムアウトが短すぎるかどうかを判断します。
- マッチルールセットを確認して、最小プレイヤーまたはチーム要件が正しく設定されているかどうかを確認します。