Nos jogos de corrida, é normal as posições iniciais dos jogadores variarem com base no desempenho que tiveram numa rodada anterior. Assim, os jogadores são incentivados a correrem rápido mesmo quando não estiverem em primeiro lugar para começar na frente de outros jogadores.
Para fazer isso, o jogo precisa saber em qual rodada dos jogadores estão no momento, e a ordem de chegada do corredor deverá persistir ao longo de todas as rodadas, mas não de todas as sessões de jogo. Uma variável de mapa fraco de sessão em Verse redefine seus dados a cada rodada, então as informações desta rodada precisam ser armazenadas com cada pessoa, usando uma variável de mapa fraco de jogador, e redefinidas após o fim do jogo.
Atualmente, cada projeto pode ter no máximo duas variáveis de mapa fraco de jogador. Se o seu projeto já tiver uma variável de mapa fraco de jogador, recomendamos fazer a segunda registrar as informações da rodada para diferenciar os dados que sempre deverão persistir dos dados que serão redefinidos após o fim do jogo ou a saída do jogador da sessão.
Também é importante saber em que rodada os jogadores estão no momento para aplicar a lógica específica da rodada e redefinir as informações dela na última rodada. Atualmente, não há nenhuma API para obter a rodada atual, então as informações também precisarão ser registradas nos dados persistentes para cada jogador.
Resumindo, você precisará de uma variável de mapa fraco de jogador com pelo menos as informações a seguir:
Ordem de chegada
Rodada concluída por último
As seções a seguir mostram definir os dados e a lógica da rodada. Você pode conferir o código completo no fim da página.
Registre a rodada concluída por último
Siga as etapas abaixo para configurar os dados persistentes de cada jogador e registar a rodada concluída por último.
Crie uma classe persistente chamada
player_circuit_infopara armazenar as informações do jogador entre rodadas. Essa classe deve ter os campos para representar a última ordem de chegada da pessoa,LastRoundFinishOrder, e sua última rodada concluída,LastCompletedRound. Esses campos são inicializados com-1para representar valores inválidos, assim você saberá quando esses campos realmente contêm informações úteis.Verse# Tracks the number of and in what order a player finished the previous round. player_circuit_info<public> := class<final><persistable>: Version:int = 0 LastRoundFinishOrder:int = -1 LastCompletedRound<public>:int = -1Crie uma variável de mapa fraco do jogador usando a classe
player_circuit_infopara fazer as informações persistirem da rodada com os jogadores.Verse# A persistable map that maps each player to # what order they finished the previous round. var CircuitInfo<public>:weak_map(player, player_circuit_info) = map{}Como prática recomendada para trabalhar com dados persistentes, crie um construtor para a classe persistente para atualizar facilmente as informações de cada pessoa. Consulte mais detalhes em Como usar construtores para atualizações parciais.
Verse# Creates a new player_circuit_info from the given older player_circuit_info. MakePlayerCircuitInfo<constructor>(OldPlayerCircuitInfo:player_circuit_info)<transacts> := player_circuit_info: Version := OldPlayerCircuitInfo.Version LastRoundFinishOrder := OldPlayerCircuitInfo.LastRoundFinishOrder LastCompletedRound := OldPlayerCircuitInfo.LastCompletedRoundAgora que você definiu as estruturas para esses dados, adicione uma função para registrar a ordem de chegada de uma pessoa e atualizar seus dados persistentes. Esta função utiliza o construtor criado na etapa anterior para atualizar parcialmente os dados para as únicas informações que realmente importam: a ordem de chegada.
Verse# Creates a new player_circuit_info for the given player with the order they finished the round in. RecordPlayerFinishOrder<public>(Agent:agent, FinishOrder:int)<decides><transacts>:void= Player := player[Agent] Player.IsActive[] PlayerCircuitInfo:player_circuit_info = if: Info := CircuitInfo[Player] then: Info else: player_circuit_info{}Crie outra função para atualizar apenas a última rodada concluída para o jogador.
Verse# Updates a player's player_circuit_info with their last completed round. UpdateRound<public>(Agent:agent, CompletedRound:int)<decides><transacts>:void= Player := player[Agent] Player.IsActive[] PlayerCircuitInfo := CircuitInfo[Player] set CircuitInfo[Player] = player_circuit_info: MakePlayerCircuitInfo<constructor>(PlayerCircuitInfo) LastCompletedRound := CompletedRoundAgora que você pode registrar a última rodada concluída para o jogador, crie uma função para calcular a última rodada concluída do jogo, verificando quais jogadores têm a última rodada registrada. Você precisa conferir todos os jogadores para considerar os jogadores que possam ter ingressado na sessão em andamento. A variável da rodada concluída por último é inicializada com
-1para representar os dados inválidos. Se algum jogador tiver um valor maior que-1, uma rodada já terminou.Verse# Returns the highest last completed round among all players. GetLastCompletedRound<public>(Players:[]player, TotalRounds:int)<transacts>:int= var LastCompletedRound:int = -1 for: Player : Players Player.IsActive[] PlayerCircuitInfo := CircuitInfo[Player] do: # Update LastCompletedRound if this player has the highest last completed round. else if:Crie um dispositivo Verse para testar se a ordem de chegada do jogador e a rodada estão funcionando como esperado. Verifique se o projeto foi configurado para ter várias rodadas, definindo a propriedade Total de Rodadas nas Configurações da Ilha.
Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= Players := GetPlayspace().GetPlayers() CurrentRound := GetLastCompletedRound(Players) + 1 Print("Current round is {CurrentRound}") for:
Redefinia as informações da rodada quando o jogador sair
Os dados persistentes do jogador relacionados às informações da rodada devem ser restaurados quando o jogador sair do jogo. Você pode fazer a inscrição no PlayerRemovedEvent do espaço de jogo para saber quando o jogador sairá.
Siga as etapas abaixo para redefinir as informações da rodada quando o jogador sair:
Crie uma função para redefinir os dados persistentes do jogador para as informações da rodada. Ou seja, é preciso definir os valores para
-1ou o valor que você decidir para representar os dados inválidos neste campo. Essa implementação habilita quais dados deverão ser redefinidos se você adicionar mais tarde outras informações à classe persistente que não deverá ser redefinida aqui.Verse# Resets a player's player_circuit_info. ResetCircuitInfo<public>(Agent:agent)<decides><transacts>:void= Player := player[Agent] Player.IsActive[] PlayerCircuitInfo := CircuitInfo[Player] set CircuitInfo[Player] = player_circuit_info: MakePlayerCircuitInfo<constructor>(PlayerCircuitInfo) LastRoundFinishOrder := -1 LastCompletedRound := -1Crie uma função chamada
OnPlayerRemovedpara redefinir as informações da rodada quando alguém sair.Verse# When a player is removed from the race, reset their circuit to prevent their # stats from showing up on billboards and player references. OnPlayerRemoved(Player:player):void= # Reset circuit info when player leaves the game. if: ResetCircuitInfo[Player] else: Print("Unable to reset circuit info for player")Defina a função
OnPlayerRemovedpara ser chamada quando alguém sai do jogo. Para isso, faça a inscrição no eventoGetPlayspace().PlayerRemovedEvent().Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerRemoved) Players := GetPlayspace().GetPlayers() CurrentRound := GetLastCompletedRound(Players) + 1Teste para verificar se um jogador que sai do jogo restaura suas informações.
Restaure as informações da rodada no final do jogo
A função OnBegin do dispositivo Verse é executada no início de todas as rodadas. É uma boa hora para determinar se o jogador tem dados persistentes inesperados, tais como se a rodada concluída por último dele é igual à quantidade total de rodadas. Se tiver, será preciso redefinir os dados do jogador. Atualmente, não há nenhuma API para saber a quantidade total de rodadas no jogo. Em vez disso, será preciso adicionar uma propriedade editável ao dispositivo Verse para obter a quantidade total de rodadas no código Verse e verificar se ela corresponde à propriedade Total de Rodadas nas Configurações da Ilha.
Siga as etapas abaixo para redefinir as informações da rodada quando o jogo acabar:
Adicione uma propriedade editável ao seu dispositivo Verse para o número total de rodadas no jogo. Total de Rodadas não deve ser menor que ou igual a
0, então restrinja os valores da propriedade a maiores ou iguais a1.Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # The total number of rounds in the race. @editable TotalRounds:type {Rounds:int where 1 <= Rounds} = 3 # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerRemoved)Atualize a função para
GetLastCompletedRoundpara redefinir os dados persistentes do jogador relacionados à rodada concluída por último se o valor for maior que o número esperado de rodadas no jogo.Verse# Returns the highest last completed round among all players. GetLastCompletedRound<public>(Players:[]player, TotalRounds:int)<transacts>:int= var LastCompletedRound:int = -1 for: Player : Players Player.IsActive[] PlayerCircuitInfo := CircuitInfo[Player] do: # If player's recorded info is greater than the total rounds for whatever reason, # then need to reset the player's circuit info because they shouldn't have more than what's allowed.Atualize a chamada para
GetLastCompletedRoundpara passar o total de rodadas como um argumento, para restaurar as informações de rodada do jogador se ele estiver em um estado inesperado.Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # The total number of rounds in the race. @editable TotalRounds:type {Rounds:int where 1 <= Rounds} = 3 # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerRemoved)Teste para verificar se as informações da rodada do jogador são redefinidas mesmo depois de jogar e concluir todas as rodadas.
Como adicionar lógica baseada na rodada atual
Agora você pode usar essas informações para ter uma lógica personalizada que depende da rodada na qual os jogadores estão. Por exemplo, você pode exibir uma tabela de liderança local relacionada à primeira rodada do jogo.
Chamar GetLastCompletedRound() sempre que você precisa saber em qual rodada o jogo está sendo jogado não é o ideal. Em vez isso, você pode fazer isso uma vez por rodada e registrar as informações dela numa variável de mapa fraco de sessão, assim todo o código Verse que está no projeto poderá acessar esse valor sem precisar recalcular tudo a cada vez.
Esse é um ótimo exemplo para mostrar as diferenças e o raciocínio para usar a variável do mapa fraco de sessão e a de jogador no seu código:
As variáveis de mapa fraco de sessão são úteis para singletons e para armazenar dados para a rodada atual que você não deseja recalcular todas as vezes.
As variáveis de mapa fraco do jogador foram projetadas para informações que precisam persistir entre várias rodadas e sessões de jogo, mas devem estar associadas a jogadores individuais.
Siga as etapas abaixo para definir uma variável de mapa fraco de sessão para armazenar a rodada atual.
Crie uma classe para armazenar as informações das rodadas. Você precisa ao menos de um campo para
CurrentRound, mas pode incluir outras informações da rodada que deseja salvar em todo o código Verse, como as posições iniciais e os veículos dos jogadores. InicializeCurrentRoundem-1para representar dados inválidos.Verseround_info := class: CurrentRound:int = -1Crie uma variável de mapa fraco de sessão usando a classe
round_infopara armazenar as informações das rodadas com a sessão.Verse# Maps the current session to its associated round info. var RoundInfo:weak_map(session, round_info) = map{}Adicione uma função getter para obter a rodada atual da variável de mapa fraco de sessão.
VerseGetRound<public>()<decides><transacts>:int= RoundInfo[GetSession()].CurrentRoundAdicione uma função para obter a rodada atual e armazene-a na variável de mapa fraco da sessão.
VerseRecordCurrentRound<public>(Players:[]player, TotalRounds:int):void= var CurrentRoundInfo:round_info = if: Info := RoundInfo[GetSession()] then: Info else: LastCompletedRound := GetLastCompletedRound(Players, TotalRounds) round_info: CurrentRound := LastCompletedRound + 1Atualize o dispositivo Verse para usar a nova função
RecordCurrentRounde chameGetRoundquando precisar saber qual rodada é.Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # The total number of rounds in the race. @editable TotalRounds:type {Rounds:int where 1 <= Rounds} = 3 # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerRemoved)
Agora que as informações estão armazenadas numa variável de mapa fraco de sessão, você pode adicionar lógica personalizada para as rodadas. Por exemplo, você pode conferir se é a primeira rodada e configurar um lobby e uma área de visualização para a tabela de liderança para os jogadores.
# Returns true if this is the first round of the game.
IsFirstRound<public>(RoundToCheck:int)<decides><transacts>:void=
RoundToCheck <= 0Por si só
Confira Modelo de pista de corrida com Persistência em Verse para saber como usar esse código em um jogo de corrida para determinar a ordem inicial dos jogadores.
Depois de conferir o modelo, tente fazer o seguinte:
Adicione mais informações sobre a rodada, por exemplo, qual veículo foi atribuído ao jogador.
Teletransporte os jogadores para áreas diferentes do mapa no início de cada rodada.
Quais outros jogos você acha que usam lógica específica para rodada?
Código completo
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# A persistable map that maps each player to
# what order they finished the previous round.
var CircuitInfo<public>:weak_map(player, player_circuit_info) = map{}
# Maps the current session to its associated round info.
var RoundInfo:weak_map(session, round_info) = map{}