Em jogos multijogador, equipes competem ou colaboram para atingir um certo objetivo. O número de jogadores em cada equipe pode ter efeitos radicais na jogabilidade, e muitos desenvolvedores ajustam essas proporções sob medida para criar um jogo agradável.
O balanceamento de equipe divide os jogadores em equipes na proporção projetada. A maioria dos jogos multijogador equilibra as equipes uniformemente para que nenhuma equipe tenha vantagem. Alguns jogos criam cenários desequilibrados intencionalmente, como por exemplo, colocar quatro jogadores contra um jogador mais poderoso. Independentemente da configuração, o equilíbrio da equipe é fundamental para que o jogo seja agradável a todas as equipes.
Ao concluir este guia, você aprenderá a equilibrar dinamicamente equipes de jogadores em tempo de execução e sempre que um novo jogador entrar no jogo. O código completo está incluído no final deste guia como referência.
Funcionalidades da linguagem Verse usadas
array: esse dispositivo usa matrizes para armazenar uma referência para cada equipe.
option: ese dispositivo usa opções para determinar se há uma equipe com menos jogadores do que a equipe em que o jogador está atualmente.
for: com a expressão for, você pode iterar sobre as matrizes que o dispositivo usa.
if: a expressão if é usada para verificar se os jogadores devem mudar para uma nova equipe com base no tamanho dela.
failure: contextos de falha são usados para acessar matrizes e controlar o fluxo do programa.
APIs Verse usadas
Subscribable: você assinará
PlayerAddedEvent()para reequilibrar dinamicamente as equipes quando um novo jogador entrar em um jogo em andamento.Teams: a classe team adiciona, remove e recupera jogadores de equipes. Você usará a classe team neste tutorial para manipular jogadores e suas atribuições de equipe diretamente.
Playspace: o espaço de jogo rastreia eventos assináveis relacionados a jogadores entrando e saindo do jogo. Ele também lida com a recuperação de listas de jogadores e equipes e procura a equipe de um determinado jogador. Neste tutorial, você assinará vários eventos do espaço de jogo e recuperará jogadores e equipes usando métodos do espaço de jogo para poder manipulá-los diretamente.
Como configurar o nível
Este exemplo usa o seguinte dispositivo.
4x Plataforma de Surgimento de Jogador: define onde o jogador surge no início do jogo.
Siga estas etapas para configurar o nível:
Adicione uma Plataforma de surgimento de jogador ao nível.
Selecione a plataforma de surgimento no Organizador para abrir o painel Detalhes.
No painel Detalhes, em Opções do Usuário:
Defina a Equipe do Jogador como Índice da Equipe com um valor de 1
Habilite Visível no Jogo
Clique na imagem para ampliar.
Duplique a plataforma de surgimento e coloque-a próximo da primeira plataforma de surgimento.
Duplique ambas as plataformas de surgimento e coloque-as mais longe do primeiro grupo de plataformas de surgimento. É aqui que os jogadores da Equipe 2 aparecerão.
Selecione as plataforma de surgimento duplicadas e, no painel Detalhes, em Opções do Usuário, altere o valor de Índice da Equipe para 2 para ambas.
No Organizador, selecione o dispositivo Configurações da Ilha para abrir seu painel Detalhes. Em Opções do Usuário - Regras do Jogo:
Defina Equipes como Índice da Equipe com um valor de 2. Este exemplo usa duas equipes, mas você pode ter qualquer número delas.
Defina o Tamanho da equipe como Dinâmico. Isso significa que o código Verse pode assumir o equilíbrio das equipes.
Defina Entrar em Andamento como Surgir, para que novos jogadores possam entrar no jogo enquanto ele estiver em execução.
Clique na imagem para ampliar.
Crie um novo dispositivo Verse chamado team_multiplayer_balancingusando o Explorador do Verse e arraste o dispositivo até o nível. (Para saber como criar um novo dispositivo em Verse, consulte Criar seu próprio dispositivo usando o Verse.)
Seu nível deve ser semelhante a esta configuração:
Dividir equipes igualmente
Equilibrar equipes no início do jogo
Esta etapa mostra como dividir os jogadores em equipes igualmente no início de um jogo e quando um novo jogador entra no jogo.
Abra o Explorador do Verse e clique duas vezes em team_multiplayer_balancing.verse para abrir o script no Visual Studio Code.
Na definição de classe
team_multiplayer_balancing, adicione uma matriz de variávelteamchamadaTeamsque armazenará referências a cada equipe em que os jogadores estão.Verseteam_multiplayer_balance := class(creative_device): # Holds the teams found with GetTeams() var Teams : []team = array{}Na função
OnBegin(), atualize a matrizTeamspara corresponder às equipes definidas anteriormente nas Configurações da Ilha. Chame a funçãoGetTeams()da APIfort_team_collectionpara obter todas as equipes no espaço de jogo.VerseOnBegin<override>()<suspends>:void= Print("Verse Device Started!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams()Encontre todos os jogadores no jogo chamando a função
GetPlayers()e salve-os em uma matriz de jogadores chamadaAllPlayers.VerseOnBegin<override>()<suspends>:void= Print("Verse Device Started!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams() AllPlayers := GetPlayspace().GetPlayers()Percorra a lista de todos os jogadores e crie equipes com o mesmo número de jogadores. Você comparará a equipe em que um jogador está atualmente com qualquer outra equipe e determinará se ela é a mais adequada para aquele jogador. Nesse caso, você pode usar a equipe ao qual um jogador é automaticamente atribuído quando o jogo começa usando
GetTeam[](já que os jogadores devem estar em uma equipe em modos de jogo com várias equipes). Note queGetTeam[]requer um parâmetro do tipo agent, mas como player é uma subclasse de agent, você pode passar um player sem conversão de tipo.VerseAllPlayers := GetPlayspace().GetPlayers() for (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): # Assign Players to a new team if teams are unbalancedComo team é uma classe interna, ela não pode ser inicializada e pode ser usada apenas como referência a um objeto de equipe existente.
Você deseja atribuir jogadores à equipe com a menor quantidade de jogadores até que todas as equipes estejam equilibradas. Para fazer isso, você precisa verificar cada jogador e, em seguida, cada equipe usando um loop
for. Você poderia usar dois loops for, um para iterar pelos jogadores e outro para iterar pelas equipes, mas, neste exemplo, você extrairá o loop for da equipe em seu próprio método. Configure o loop for do jogador obtendo uma referência a cada jogador e, em seguida, faça referência a cada equipe em que eles estão em uma constante chamadaCurrentTeam.Crie uma nova variável de número inteiro
TeamSizee inicialize-a como0. Em seguida, defina-a para ser igual ao tamanho da equipe em que esse jogador está atualmente. ComoGetAgents[]é uma expressão falível, você precisa incluir esse conjunto em uma instrução if.Versefor (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): # Assign Players to a new team if teams are unbalanced var TeamSize : int = 0 if(set TeamSize = GetPlayspace().GetTeamCollection().GetAgents[CurrentTeam].Length): Print("Size of this player's starting team is {TeamSize}")Crie um método chamado
FindSmallestTeam(). Isso retornará uma equipe opcional (?team) ao passarTeamSizecomo um argumento e tratará de encontrar e retornar a equipe com a menor quantidade de jogadores. Inicialize uma nova opção de equipe chamadaSmallestTeamdentro deFindSmallestTeam(). Você usará uma opção aqui porque um jogador pode já estar na menor equipe quando você chamarFindSmallestTeam().Como a opção
SmallestTeamusa falso como padrão, ela permaneceráfalsose nenhuma equipe menor for encontrada. SeFindSmallestTeam()retornarfalso, você saberá definitivamente que o jogador já estava na menor equipe. Você também precisa inicializar uma variável intCurrentTeamSizepara o valor deTeamSize. Você precisa queCurrentTeamSizeseja variável para que possa atualizá-lo para o tamanho de qualquer outra equipe que encontrar com menos jogadores.VerseFindSmallestTeam(CurrentTeamSize : int) : ?team= var SmallestTeam : ?team = false var TeamSize : int = CurrentTeamSizeComo
TeamSizerastreia o tamanho deSmallestTeam, você precisa compará-lo com o tamanho de cada equipe. Percorra cada equipe e obtenha seu tamanho em um int localCandidateTeamSize. SeCandidateTeamSizefor menor queTeamSize, definaSmallestTeamcomo essa equipe eTeamSizecomo o tamanho dessa equipe.A condição
TeamSize > CandidateTeamSizeé uma condição de filtro porque é verificada entre os parênteses do loop for. O uso de uma condição de filtro garante que o código dentro do loop seja executado somente se a condição de filtro for bem-sucedida. Isso garante queSmallestTeamserá definido como a equipe com menos jogadores, se alguma for encontrada. Se nenhuma equipe com menos jogadores for encontrada,SmallestTeampermanecerá falso.Por último, retorne
SmallestTeamuma vez que todas as equipes tenham sido verificadas.Versefor(Team : Teams, CandidateTeamSize := GetPlayspace().GetTeamCollection().GetAgents[Team].Length, TeamSize > CandidateTeamSize): set SmallestTeam = option{Team} set TeamSize = CandidateTeamSize Print("Found a team with less players: {CandidateTeamSize}") return SmallestTeamEm
OnBegin(), crie uma nova opção de equipe chamadaSmallestTeamdentro do loopfore inicialize-a com o valor deFindSmallestTeam()quando passarTeamSizecomo um argumento.VerseSmallestTeam : ?team = FindSmallestTeam(TeamSize)Em seguida, tente acessar o valor na variável opcional
SmallestTeam. Se o valor for false, o jogador já estava na menor equipe, e nenhuma atribuição é necessária. Caso contrário, convém atribuir o jogador à nova equipe. Como muitos métodos não nos permitem passar diretamente uma opção como um argumento, você deve extrair o valor para uma variável localTeamToAssign. Você pode tentar atribuir um jogador a essa equipe usandoAddToTeam[player, team]. Observe que essa atribuição falhará se você tentar atribuir um jogador a uma equipe em que ele já esteja. No entanto, isso não terá efeito negativo, pois o loopforapenas iterará para o próximo jogador e deixará o primeiro em sua equipe original.Verseif (TeamToAssign := SmallestTeam?, GetPlayspace().GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]): Print("Attempting to assign player to a new team")
OnBegin()deve se parecer com o bloco de código abaixo.VerseOnBegin<override>()<suspends> : void = Print("Verse Device Started!") set Teams = Self.GetPlayspace().GetTeamCollection().GetTeams() Print("Beginning to Assign Players") Playspace := GetPlayspace() AllPlayers := Playspace.GetPlayers() for (TeamPlayer : AllPlayers, CurrentTeam := Playspace.GetTeamCollection().GetTeam[TeamPlayer]): var TeamSize : int = 0 if(set TeamSize = Playspace.GetTeamCollection().GetAgents[CurrentTeam].Length): Print("Size of this player's starting team is {TeamSize}")
Lidar com a entrada de um jogador no meio do jogo
Como você também deseja equilibrar automaticamente as equipes para um jogo em andamento, precisará assinar o evento que é acionado quando um novo jogador entra. Como você não deseja repetir todo o código que acabou de escrever, pode refatorá-lo em um método comum.
Crie um método chamado
BalanceTeams()e mova todo o código depois de definir a variávelTeamsusandoGetTeams(). Ele é chamado no métodoOnBegin(), para que as equipes sejam equilibradas quando o jogo começar.BalanceTeams()deve ter a seguinte aparência.VerseBalanceTeams() : void = AllPlayers := GetPlayspace().GetPlayers() for (TeamPlayer : AllPlayers, CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]): var TeamSize : int = 0 if(set TeamSize = GetPlayspace().GetTeamCollection().GetAgents[CurrentTeam].Length): Print("Size of this player's starting team is {TeamSize}") SmallestTeam : ?team = FindSmallestTeam(TeamSize) if (TeamToAssign := SmallestTeam?, GetPlayspace().GetTeamCollection().AddToTeam[TeamPlayer, TeamToAssign]): Print("Attempting to assign player to a new team")Crie outro método chamado
OnPlayerAdded()que contém uma chamada paraBalanceTeams(). Embora você não vá usar a variávelplayer, a definição do método requer essa variável, uma vez que você fez o registro emPlayerAddedEvent()usando esse método. Consulte a página Codificar interações entre dispositivos para obter mais detalhes sobre eventos assináveis.VerseOnPlayerAdded(InPlayer : player) : void = Print("A new Player joined, assigning them to a team!") BalanceTeams()Em
OnBegin(), assinePlayerAddedEvent()usandoOnPlayerAdded. Agora, quando um jogador entrar no jogo,OnPlayerAddedchamaráBalanceTeams()para equilibrar automaticamente as equipes.VerseOnBegin<override>()<suspends> : void = GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded) Print("Beginning to balance teams") BalanceTeams()Salve o script no Visual Studio Code e clique em Compilar código Verse para compilar seu script.
Clique em Iniciar Sessão na barra de ferramentas do UEFN para testar o nível.
Ao testar seu nível, você deve ver o tamanho de cada equipe, bem como as equipes menores encontradas pelo script impressas no log de saída. Os jogadores devem ser equilibrados entre as equipes de maneira uniforme, e um novo jogador que entrar no jogo deverá manter esse equilíbrio.
Script completo
O código a seguir é o script completo para um dispositivo que equilibra automaticamente equipes de jogadores.
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
team_multiplayer_balance := class(creative_device):
# Holds the teams found with GetTeams()
var Teams : []team = array{}
OnBegin<override>()<suspends> : void =
Print("Verse Device Started!")
Por si só
Ao concluir este guia, você aprendeu a criar um dispositivo usando o Verse que equilibra equipes de jogadores automaticamente.
Usando o que você aprendeu, tente criar equipes intencionalmente desequilibradas para modos de jogo assimétricos, como um jogador contra quatro jogadores.