アルゴリズムを調べる
ゲームの開始時には、それぞれのチームのプレイヤー数が適切になるようにバランスを取る必要があります。
ゲーム内でのプレイヤーのバランスが対称的で、プレイヤーがチーム間で均一に割り当てられる場合とは異なり、チームのバランスを非対称に取ることは、それぞれのチームに 相対的な 数のプレイヤーが存在することを意味します。言い換えると、チーム サイズは相対比率に基づくものになります。
たとえば、あるチームには他のチームの 2 倍のプレイヤー数を割り当てたい場合などがあります。 この場合、プレイヤーが参加するたびに、この相対比率を維持しながらチーム間のバランスを調整する必要があります。 あるチームをより強力に保つ、または他のチームとは異なる能力を持たせるゲーム モードでは、バランスを非対称に調整して、それぞれのチームにプレイヤーを慎重に振り分けることで、よりスムーズなプレイヤー エクスペリエンスを実現できます。
この例では、最大プレイヤー数がより大きいチーム (この場合は「Defenders」チーム) に、最大プレイヤー数がより小さいチーム (「Infiltrators」チームなど) よりも多くのプレイヤーが常に存在するようにする必要があります。
プレイヤーを正しく振り分けるには、それぞれのプレイヤーを、最大プレイヤー数との差分が最も大きいチームに割り当てます。
そのためには、新しいプレイヤーごとにそれぞれのチームをチェックして、そのチームと、プレイヤーを割り当てる先のチームの最大プレイヤー数と現在のプレイヤー数の両方への参照を格納する必要があります。 現在のプレイヤー数から最大プレイヤー数を引くことで、最大数との差分を得ることができます。 最大数との差分が最も大きいチームを特定したら、プレイヤーをそのチームに割り当てるように設定します。
これをそれぞれのチームでイテレートすることで、差分が最も大きいチームを確実に特定することができます。
アルゴリズムを定義する
以下の手順では、ゲームの開始時に各チームのプレイヤー数のバランスを非対称に調整する方法を示します。
- 新しい
BalanceTeams()という名前のメソッドをtriad_infiltration_gameクラスに追加します。このメソッドでは、最大プレイヤー数との差分が最も大きいチームにプレイヤーを割り当てます。# ゲーム内のすべてのチームのすべてのプレイヤーのバランスを調整します BalanceTeams():void= Logger.Print("Beginning to balance teams") - ゲーム内のすべてのプレイヤーを取得し、変数配列
AllPlayersに格納します。次に、AllPlayersをシャッフルします。これにより、プレイヤーは最初にゲームに参加した順序ではなく、ランダムにチームに割り当てられるようになります。# ゲーム内のすべてのチームのすべてのプレイヤーのバランスを調整します BalanceTeams():void= Logger.Print("Beginning to balance teams") var AllPlayers:[]player := GetPlayspace().GetPlayers() set AllPlayers = Shuffle(AllPlayers) - 次に、すべてのプレイヤーをイテレートして、最大プレイヤー数との差分が最も大きいチームにそれらのプレイヤーを割り当てます。これは次のステップで作成する
FindTeamWithLargestDifference()という名前のヘルパー関数を通じて行いますが、まず最初に、プレイヤーの割り当て先となる、TeamToAssignと呼ばれる任意の変数を初期化して、それをFindTeamWithLargestDifference()から返される値に設定します。for (TeamPlayer : AllPlayers): var TeamToAssign:?team = false set TeamToAssign = FindTeamWithLargestDifference() triad_infiltration_gameクラス定義内に関数FindTeamWithLargestDifference()を作成します。この関数では、最大プレイヤー数との差分が最も大きいチームを特定する処理が行われ、任意のteamが返されます。返されるteamは、差分が最も大きいチームに当該のプレイヤーがすでに存在する場合に、そのプレイヤーの再割り当てを回避するために、任意 (option) にすることをお勧めします。# 最大プレイヤー数と現在のプレイヤー数との差分が最も大きい # チームを特定します FindTeamWithLargestDifference():?team = Logger.Print("Attempting to find smallest team")TeamToAssignという名前の任意のチーム変数を初期化します。この変数には、プレイヤー数における差分が最も大きいチームへの参照と、プレイヤー数の差分をトラックするLargestDifference整数値が格納されます。# 最大プレイヤー数と現在のプレイヤー数との差分が最も大きい # チームを特定します。 FindTeamWithLargestDifference():?team = Logger.Print("Attempting to find smallest team") var TeamToAssign:?team = false var LargestDifference:int = 0- 次に、一連のチームをイテレートして、それぞれのチームの現在のサイズと最大サイズの両方を取得します。
var TeamToAssign:?team = false var LargestDifference:int = 0 for: CandidateTeam : Teams CurrentTeamSize := GetPlayspace().GetTeamCollection().GetAgents[CandidateTeam].Length MaximumTeamSize := TeamsAndTotals[CandidateTeam] - それぞれのチームの
DifferenceFromMaximumを計算します。これは、当該のチームの最大サイズと、そのチームに現在含まれているプレイヤーの数との差分です。チームの差分がLargestDifferenceよりも大きい場合はLargestDifferenceをDifferenceFromMaximumに設定し、TeamToAssignをoptionでラップします。for: CandidateTeam:Teams CurrentTeamSize := GetPlayspace().GetTeamCollection().GetAgents[CandidateTeam].Length MaximumTeamSize := TeamsAndTotals[CandidateTeam] do: Logger.Print("Checking a team...") Logger.Print("Maximum size of this team is {MaximumTeamSize}") DifferenceFromMaximum := MaximumTeamSize - CurrentTeamSize Logger.Print("Difference from maximum is {DifferenceFromMaximum}") if(LargestDifference < DifferenceFromMaximum): set LargestDifference = DifferenceFromMaximum set TeamToAssign = option{CandidateTeam} Logger.Print("Found a team under maximum players: {DifferenceFromMaximum}") - 最後に
TeamToAssignを返します。FindTeamWithLargestDifference()コードは次のようになるはずです。# 最大プレイヤー数と現在のプレイヤー数との差分が最も大きい # チームを特定します。 FindTeamWithLargestDifference():?team = Logger.Print("Attempting to find smallest team") var TeamToAssign:?team = false var LargestDifference:int = 0 for: CandidateTeam:Teams CurrentTeamSize := GetPlayspace().GetTeamCollection().GetAgents[CandidateTeam].Length MaximumTeamSize := TeamsAndTotals[CandidateTeam] do: Logger.Print("Checking a team...") Logger.Print("Maximum size Maximum size of team {CandidateTeamIndex + 1} is {MaximumTeamSize}") DifferenceFromMaximum := MaximumTeamSize - CurrentTeamSize Logger.Print("Difference from minimum is {DifferenceFromMaximum}") if(LargestDifference < DifferenceFromMaximum): set LargestDifference = DifferenceFromMaximum set TeamToAssign = option{CandidateTeam} Logger.Print("Found a team under minimum players: {DifferenceFromMaximum}") return TeamToAssign BalanceTeams()に戻り、FortTeamCollection.AddToTeam[]関数を介してプレイヤーを新しいチームに割り当てます。この割り当てが失敗する場合は、当該のプレイヤーが差分の最も小さいチームにすでに割り当て済みであることを意味します。var TeamToAssign:?team = false set TeamToAssign = FindTeamWithLargestDifference() if (AssignedTeam := TeamToAssign?, FortTeamCollection.AddToTeam[TeamPlayer, AssignedTeam]): Logger.Print("Attempting to assign player to a new team")BalanceTeams()関数は次のようになるはずです。# ゲーム内のすべてのチームのすべてのプレイヤーのバランスを調整します BalanceTeams():void= Logger.Print("Beginning to balance teams") var AllPlayers:[]player := GetPlayspace().GetPlayers() set AllPlayers = Shuffle(AllPlayers) Logger.Print("AllPlayers Length is {AllPlayers.Length}") for (TeamPlayer : AllPlayers): var TeamToAssign:?team = false set TeamToAssign = FindTeamWithLargestDifference() if (AssignedTeam := TeamToAssign?, FortTeamCollection.AddToTeam[TeamPlayer, AssignedTeam]): Logger.Print("Assigned player to a new team")
プレイヤーをスポーン エリアにテレポートする
プレイヤーが差分が最も大きいチームに割り当てられているのに、正しいエリアにスポーンされない場合があります。 原因は、プレイヤーが新しいチームのバランス調整前にスポーンされるからです。 これに対応するために、チームのバランス調整後にプレイヤーをスポーンにテレポートするための新しい関数を作成します。
triad_infiltration_gameクラス定義内に関数TeleportPlayersToStartLocations()を作成します。この関数は、バランス調整の完了後にプレイヤーをスポーンにテレポートします。# チームのバランス調整後にプレイヤーをチームのスポーンにテレポートさせます。 TeleportPlayersToStartLocations():void= Logger.Print("Teleporting players to start locations")forループ内で配列Teamsのそれぞれをイテレーションし、そのチームのインデックスを取得して変数TeamIndexに格納します。# チームのバランス調整後にプレイヤーをチームのスポーンにテレポートさせます。 TeleportPlayersToStartLocations():void= Logger.Print("Teleporting players to start locations") for: TeamIndex -> PlayerTeam:TeamsPlayerTeamを使用してGetAgents[]を呼び出してPlayerTeamのプレイヤーを取得します。その後、TeamIndexを使用してTeleporters配列にインデックスを付け、変数TeamTeleporterに格納することで、そのチームに紐づいているテレポーターを取得します。そのテレポーターのトランスフォームを変数Transform.に格納します。# チームのバランス調整後にプレイヤーをチームのスポーンにテレポートさせます。 TeleportPlayersToStartLocations():void= Logger.Print("Teleporting players to start locations") for: TeamIndex -> PlayerTeam:Teams TeamPlayers := GetPlayspace().GetTeamCollection().GetAgents[PlayerTeam] TeamTeleporter := Teleporters[TeamIndex] Transform := TeamTeleporter.GetTransform()Teamsにおけるチームの順序がTeleportersのテレポーターの順序に一致するようにしてください。Infiltrator が Team 1 の場合、Teleportersの最初のテレポートは Infiltrator になります。これらの値が正しいことをエディタ内で再確認してください。- 2 つ目の
forループで、TeamPlayersの各プレイヤーをイテレーションし、Respawn()とTransformの平行移動と回転を使用して、テレポーターのトランスフォームにリスポーンします。TeleportPlayersToStartLocations()関数は次のようになるはずです。# チームのバランス調整後にプレイヤーをチームのスポーンにテレポートさせます。 TeleportPlayersToStartLocations():void= Logger.Print("Teleporting players to start locations") for: TeamIndex -> PlayerTeam:Teams TeamPlayers := GetPlayspace().GetTeamCollection().GetAgents[PlayerTeam] TeamTeleporter := Teleporters[TeamIndex] Transform := TeamTeleporter.GetTransform() do: for(TeamPlayer:TeamPlayers): TeamPlayer.Respawn(Transform.Translation, Transform.Rotation) Logger.Print("Teleported this player to their start location") OnBegin()に、AllPlayersのシャッフル後にBalanceTeams()への呼び出しを追加します。これにより、プレイヤーが毎回同じチームに割り当てられるのではなく、ランダムな順序でプレイヤーのバランスが調整されることが確実になります。次に、TeleportPlayersToStartLocations()を呼び出して、プレイヤーを開始位置にテレポートします。OnBegin<override>()<suspends> : void = # すべてのチームを取得します。 set Teams = GetPlayspace().GetTeamCollection().GetTeams() # Save the teams to later reference them set MaybeInfiltrators = option{Teams[0]} set MaybeAttackers = option{Teams[1]} set MaybeDefenders = option{Teams[2]} if: Infiltrators := MaybeInfiltrators? Attackers := MaybeAttackers? Defenders := MaybeDefenders? Logger.Print("Found all three teams") set TeamsAndTotals[Infiltrators] = MaximumInfiltrators set TeamsAndTotals[Attackers] = MaximumAttackers set TeamsAndTotals[Defenders] = MaximumDefenders Logger.Print("Set all three teams in TeamsAndTotals") then: BalanceTeams() TeleportPlayersToStartLocations() else: Logger.Print("Couldn't find all teams, make sure to assign the correct teams in your island settings.")-
スクリプトを保存してコンパイルし、UEFN ツールバーの [Launch Session (セッションを起動)] をクリックしてレベルをプレイテストします。レベルをプレイテストすると、それぞれのプレイヤーが差分が最も大きいチームに割り当てられて、そのチームのスポーン エリアにスポーンされます。ログを使ってこの動作を確認してください。プレイヤーの数が最大プレイヤー数よりも少ない場合は、
triad_infiltration_gameでチームごとの最大プレイヤー数を調整して、この機能をテストできます。たとえば、一人でテストを行う際は、プレイヤーを割り当てようとしている先のチームの最大プレイヤー数を、他の 2 チームよりも大きく設定してみてください。割り当て先が Attackers の場合はMaximumAttackersをより大きく設定します。割り当て先が Infiltrators の場合はMaximumInfiltratorsをより大きく設定します。
次のステップ
このチュートリアルの 次のステップ では、ゲームの開始時とプレイヤーのスポーン時に、プレイヤーに武器を付与する方法について説明します。