알고리즘 파악하기
게임이 시작되면 각 팀에 적절한 수의 플레이어가 할당되도록 밸런싱해야 합니다.
플레이어 밸런싱이 대칭적이고 팀 간에 플레이어 수가 동일하게 분배되는 게임과 달리, 비대칭 팀 밸런싱이란 곧 팀별 플레이어 수가 상대적 이라는 뜻입니다. 즉, 팀 크기가 상대적 비율을 따르게 됩니다.
예를 들어 한 팀의 플레이어 수가 다른 팀보다 항상 두 배 더 많아야 할 수 있습니다. 플레이어가 게임에 합류하면 이러한 상대적 비율을 유지하는 방식으로 밸런싱해야 합니다. 한쪽 팀이 더 강력하거나 팀별로 서로 다른 능력을 가진 게임 모드에서 비대칭 밸런싱은 각 팀의 플레이어 수를 신중하게 분배하여 보다 원활한 플레이 경험을 조성합니다.
이 예시에서는 최대 플레이어 수가 많은 팀(여기에서는 방어자)이 최대 플레이어 수가 적은 팀(여기에서는 침투자)보다 항상 더 많은 플레이어를 보유하게 해야 합니다.
플레이어들을 올바르게 분배하려면 최대 플레이어 수와 현재 인원 수가 가장 크게 차이 나는 팀에 플레이어를 우선 배치해야 합니다.
이렇게 하려면 플레이어가 새로 추가될 때마다 각 팀을 확인하고, 팀별 최대 및 현재 플레이어 수와 이 플레이어를 할당할 팀에 대한 레퍼런스를 모두 저장해야 합니다. 현재 플레이어 수에서 최대 플레이어 수를 빼면 그 차이를 구할 수 있습니다. 차이가 가장 큰 팀을 파악했다면 플레이어를 해당 팀에 할당하도록 설정하면 됩니다.
각 팀별로 반복작업을 하면 어느 팀이 가장 큰 차이를 보이는지 파악할 수 있습니다.
알고리즘 정의하기
이 단계에서는 게임 시작 시점에서 팀 플레이어 수를 비대칭으로 밸런싱하는 방법을 살펴봅니다.
- 새 메서드
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을 옵션으로 설정하여 이미 가장 큰 차이를 보이는 팀에 소속된 플레이어는 밸런싱 대상이 되지 않도록 해야 합니다.# 최대 플레이어 수와 현재 플레이어 수가 가장 큰 차이를 보이는 # 팀을 찾습니다. 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의 순간이동 장치 순서와 일치하는지 확인합니다. 침투자가 팀 1이라면Teleporters의 첫 번째 순간이동 장치도 해당 침투자를 위한 것이어야 합니다. 이 값이 정확한지 에디터에서 다시 한번 확인합니다.- 이제 두 번째
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() # 나중에 레퍼런스하기 위해 팀을 저장합니다. 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에서 팀별 최대 플레이어 수를 조정하여 이 기능을 테스트할 수 있습니다. 예를 들어 혼자 테스트할 때는 플레이어를 할당할 팀의 최대 플레이어 수를 다른 팀보다 높게 설정합니다. 즉, 공격자로 플레이어를 배치하고 싶은 경우에는MaximumAttackers를 더 높게 설정하고, 침투자로 플레이어를 배치하고 싶은 경우에는MaximumInfiltrators를 더 높게 설정하면 됩니다.
다음 단계
이 튜토리얼의 다음 단계에서는 게임 시작 및 플레이어 생성 시점에서 플레이어에게 무기를 지급하는 방법을 살펴봅니다.