すべてをまとめる - パーティでプレイ - (Unity モジュール)
注釈:本資料はAI技術を用いて翻訳されています。
UI をパーティでプレイのフローに接続する
前のセクションでは、ゲームプレイに関連するパーティイベントを処理し、通知とプロンプトを適切に表示する関数を作成しました。パーティリーダーのみがゲームセッションとマッチメイキングを開始できるようにするため、このセクションでは必要な検証を実行する関数を紹介します。
-
PlayingWithPartyWrapper_Starterクラスを開き、以下の関数を作成してパーティメンバーのゲームセッションステータスを追跡します。これを使用して、パーティメンバーがアクティブなゲームセッションに参加しているかどうかを検証します。private void UpdatePartyMemberGameSessionStatus()
{
if (!IsInParty)
{
return;
}
MenuCanvas menuCanvas = MenuManager.Instance.GetCurrentMenu();
bool isInMatchLobby = menuCanvas != null && menuCanvas is MatchLobbyMenu;
bool isInGameplay = SceneManager.GetActiveScene().buildIndex is GameConstant.GameSceneBuildIndex;
bool isInGameSession = isInMatchLobby || isInGameplay;
// No need to update if the status is the same.
if (isInGameSession == cachedInGameStatus)
{
return;
}
// Update party member game session status
Session.GetPartyDetails(CachedParty.id, (result) =>
{
if (result.IsError)
{
BytewarsLogger.LogWarning($"Update party member game session status failed. Error {result.Error.Code}: {result.Error.Message}");
return;
}
SessionV2PartySession partySession = result.Value;
SessionV2PartySessionUpdateRequest request = new();
request.version = partySession.version;
request.attributes = partySession.attributes;
// Parse old statuses.
Dictionary<string /*userId*/, bool /*isInGameSession*/> memberGameSessionStatuses = new();
if (request.attributes.TryGetValue(
PlayingWithPartyModels.PartyMembersGameSessionStatusesKey, out object value))
{
memberGameSessionStatuses = JObject.FromObject(value).ToObject<Dictionary<string, bool>>();
}
// Update current player game session status.
memberGameSessionStatuses[GameData.CachedPlayerState.PlayerId] = isInGameSession;
request.attributes[PlayingWithPartyModels.PartyMembersGameSessionStatusesKey] = memberGameSessionStatuses;
Session.PatchUpdateParty(partySession.id, request, (patchResult) =>
{
if (result.IsError)
{
BytewarsLogger.LogWarning($"Update party member game session status failed. Error {patchResult.Error.Code}: {patchResult.Error.Message}");
return;
}
BytewarsLogger.Log($"Update party member game session status success. Current status: {isInGameSession}");
cachedInGameStatus = isInGameSession;
});
});
} -
次に、以下の関数を作成してゲームセッションの作成を検証します。この関数は、ゲームセッションの開始者がパーティリーダーであるかどうかを確認し、他のパーティメンバーがアクティブなゲームセッションに参加していないことを検証します。
private async UniTask<bool> IsValidToStartPartyGameSession()
{
// If not in party session, no need to validate.
if (!IsInParty)
{
return true;
}
// Only party leader is able to start party game session.
if (!IsPartyLeader)
{
MenuManager.Instance.PushNotification(new PushNotificationModel()
{
Message = PlayingWithPartyModels.PartyGameSessionMemberSafeguardMessage,
UseDefaultIconOnEmpty = false
});
return false;
}
// Get party member game session status.
UniTaskCompletionSource<bool> task = new();
Session.GetPartyDetails(CachedParty.id, (result) =>
{
if (result.IsError)
{
task.TrySetResult(false);
return;
}
// Parse party member game session status.
Dictionary<string /*userId*/, bool /*isInGameSession*/> memberGameSessionStatuses = new();
if (result.Value.attributes.TryGetValue(
PlayingWithPartyModels.PartyMembersGameSessionStatusesKey, out object value))
{
memberGameSessionStatuses = JObject.FromObject(value).ToObject<Dictionary<string, bool>>();
}
// Only validate active members.
string[] activeMembers = result.Value.members.
Where(x => x.StatusV2 == SessionV2MemberStatus.JOINED).
Select(x => x.id).ToArray();
memberGameSessionStatuses = memberGameSessionStatuses
.Where(x => activeMembers.Contains(x.Key))
.ToDictionary(x => x.Key, x => x.Value);
// Check if all member are available for new game session.
bool isAllMemberAvailable = memberGameSessionStatuses.All(x => x.Value == false);
if (!isAllMemberAvailable)
{
MenuManager.Instance.PushNotification(new PushNotificationModel()
{
Message = PlayingWithPartyModels.PartyGameSessionLeaderSafeguardMessage,
UseDefaultIconOnEmpty = false
});
}
task.TrySetResult(isAllMemberAvailable);
});
return await task.Task;
} -
次に、以下の関数を作成してゲームセッションへの参加を検証します。参加するゲームセッションに十分なスペースがあるかどうかを確認します。
private async UniTask<bool> IsValidToJoinPartyGameSession(SessionV2GameSession gameSession)
{
if (!IsInParty)
{
return true;
}
if (!await IsValidToStartPartyGameSession())
{
return false;
}
// Count active members with joined status
int activeMemberCount = gameSession.members.Count(m => m.StatusV2 == SessionV2MemberStatus.JOINED);
bool isAvailable = !gameSession.IsFull && gameSession?.configuration.maxPlayers - activeMemberCount >= CachedParty?.members.Length;
// Notify that no more slots to join the session.
if (!isAvailable)
{
MenuManager.Instance.PushNotification(new PushNotificationModel()
{
Message = PlayingWithPartyModels.JoinPartyGameSessionSafeguardMessage,
UseDefaultIconOnEmpty = false
});
}
return isAvailable;
} -
次に、以下の関数を作成してマッチメイキングの開始を検証します。チームごとの最大プレイヤー数が1より大きいことを確認することで、ゲームモードがパーティでのプレイをサポートしているかどうかをチェックします。
private async UniTask<bool> IsValidToStartPartyMatchmaking(InGameMode gameMode)
{
if (!IsInParty)
{
return true;
}
if (!await IsValidToStartPartyGameSession())
{
return false;
}
// No need to validate if there is only one member in party.
if (CachedParty?.members.Length <= 1)
{
return true;
}
// Check whether matchmaking with party is supported using the specified game mode.
bool isSupported = gameMode is InGameMode.MatchmakingTeamDeathmatch or InGameMode.CreateMatchTeamDeathmatch;
if (!isSupported)
{
MenuManager.Instance.PushNotification(new PushNotificationModel()
{
Message = PlayingWithPartyModels.PartyMatchmakingSafeguardMessage,
UseDefaultIconOnEmpty = false
});
}
return isSupported;
} -
次に、これらの関数をゲーム内の関連する UI 要素にバインドします。この場合、プレイヤーが Start Matchmaking、Create Game Session、または Join Game Session ボタンをクリックしたときにトリガーされる必要があります。Byte Wars では、バインディング用のデリゲートを用意しているため、
OnEnable()関数に以下のコードを追加するだけです。private UnityAction<Scene, LoadSceneMode> onSceneLoaded;
private Action<MenuCanvas> onMenuChanged;
...
private void OnEnable()
{
// ..
OnValidateToStartMatchmaking = IsValidToStartPartyMatchmaking;
OnValidateToStartGameSession = IsValidToStartPartyGameSession;
OnValidateToJoinGameSession = IsValidToJoinPartyGameSession;
onSceneLoaded = (scene, mode) => UpdatePartyMemberGameSessionStatus();
onMenuChanged = (menu) => UpdatePartyMemberGameSessionStatus();
SceneManager.sceneLoaded += onSceneLoaded;
MenuManager.OnMenuChanged += onMenuChanged;
} -
最後に、ラッパーが非初期化されるときにこれらの関数をアンバインドします。これを行うには、
OnDisable()関数に以下のコードを追加します。private void OnDisable()
{
// ..
OnValidateToStartMatchmaking = gameMode => UniTask.FromResult(true);
OnValidateToStartGameSession = () => UniTask.FromResult(true);
OnValidateToJoinGameSession = sessionId => UniTask.FromResult(true);
SceneManager.sceneLoaded -= onSceneLoaded;
MenuManager.OnMenuChanged -= onMenuChanged;
} -
これで、プレイヤーが Byte Wars のオンラインセッションに関連する UI にアクセスしようとすると、パーティでのプレイに関連する機能を実行する前に検証が実行されます。これらの UI には、マッチメイキング用の Quick Play へのアクセス、パーティセッションまたはマッチセッションの作成、ゲームセッションの閲覧が含まれます。
-
IsValidToStartPartyGameSession()関数は、プレイヤーが Play Online > Create A Session > Create Elimination および Play Online > Create Match Session > [任意のゲームモードボタン] > [任意のネットワークモードボタン] をクリックしたときに呼び出されます。 -
IsValidToJoinPartyGameSession()関数は、プレイヤーが Play Online > Browse Matches から Join ボタンをクリックしたときに呼び出されます。 -
IsValidToStartPartyMatchmaking()関数は、プレイヤーが Play Online > Quick Play > [任意のゲームモードボタン] > [任意のネットワークモードボタン] から Server Type をマッチメイキングとして選択したときに呼び出されます。
-
-
「パーティ内では Elimination モードでマッチメイキングできません」や「オンラインセッションを開始できるのはパーティリーダーのみです」などの検証メッセージを表示する通知が表示されます。
リソース
-
このチュートリアルセクションで使用されているファイルは、Unity Byte Wars GitHub リポジトリで入手できます。