Esta seção inclui o código completo para adicionar aos arquivos Verse que você criou.
Código completo
Existem vários arquivos Verse neste projeto:
-
heartbeat.verse: Veja abaixo o código completo do arquivo.
-
base_team.verse: Veja abaixo o código completo do arquivo.
-
hunter_team.verse: Veja abaixo o código completo do arquivo.
-
prop_team.verse: Veja abaixo o código completo do arquivo.
-
round_timer.verse: Veja abaixo o código completo do arquivo.
-
waiting_for_more_players.verse: Veja abaixo o código completo do arquivo.
heartbeat.verse
~~~(verse) using { /Fortnite.com/Characters } using { /Fortnite.com/Devices } using { /Fortnite.com/UI } using { /UnrealEngine.com/Temporary/SpatialMath } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/UI } using { /Verse.org/Colors } using { /Verse.org/Simulation }
log_heart_beat := class(log_channel){}
Essas mensagens são usadas para notificar um agente de adereço com uma mensagem (ou para ocultá-la) quando ele precisar se mover para evitar que seus batimentos cardíacos fiquem visíveis.
HeartBeatWarningMessage
Esta classe expôs as propriedades editáveis da pulsação ao dispositivo prop_hunt.
heart_beat := class
@editável # O número de segundos antes que um agente de adereço deva se mover até que o batimento cardíaco revele sua posição. MoveTime:float = 15.0
@editável # O tempo em segundos restante até que o aviso do batimento cardíaco apareça. Não deve ser maior que "HeartBeatTimer". WarningTime:float = 5.0
@editável # Uma matriz de dispositivos de efeitos visuais de batimentos cardíacos. Existe uma por jogador. AgentVFX:[]heartbeat_vfx = array{}
@editável # O dispositivo reprodutor de áudio usado para reproduzir os efeitos sonoros (SFX) de batimentos cardíacos. SFXPlayer:radio_device = radio_device{}
# Esse mapa associa uma IU para exibir o aviso de batimentos cardíacos para cada agente adereço. var WarningUI:[agent]heartbeat_warning_ui = map{}
# Rastreia quantos jogadores têm um batimento cardíaco ativo, para que possamos gerenciar o dispositivo de efeitos sonoros. var NumberOfHeartBeats:int = 0
# Configura a IU de batimento cardíaco para o agente. SetUpUI(PropAgent:agent):void = if: not WarningUI[PropAgent] AsPlayer := player[PropAgent] PlayerUI := GetPlayerUI[AsPlayer] then: UIData:heartbeat_warning_ui = heartbeat_warning_ui{} UIData.CreateCanvas() PlayerUI.AddWidget(UIData.Canvas, player_ui_slot{ZOrder := 1}) if (set WarningUI[PropAgent] = UIData) {}
# Ativa os efeitos visuais e sonoros de batimentos cardíacos para o jogador especificado. Enable(PropAgent:agent, HeartBeatVFXData:heartbeat_vfx):void = if: # Obtém o personagem que é usado para encontrar a posição do agente de adereço na cena. Character := PropAgent.GetFortCharacter[] then:
# Define a posição do efeito visual de batimento cardíaco para a posição do agente de adereço. HeartBeatVFXData.Activate(Character.GetTransform())
# Incrementa a contagem de batimentos cardíacos e, se esse for o primeiro batimento cardíaco reproduzido, precisamos reproduzir o áudio para iniciá-lo. set NumberOfHeartBeats += 1 if (NumberOfHeartBeats = 1) then SFXPlayer.Play()
# Registra o agente de adereço no dispositivo de reprodução de áudio, para que o áudio do batimento cardíaco seja reproduzido dessa posição. SFXPlayer.Register(PropAgent) else: Logger.Print("Personagem, índice ou HeartBeatVFXData não encontrado. Não é possível iniciar batimento cardíaco.")
# Limpa os efeitos visuais e sonoros do batimento cardíaco para o agente adereço especificado. Disable(PropAgent:agent, HeartBeatVFXData:heartbeat_vfx):void = Logger.Print("Desabilitando batimento cardíaco.")
# Desativa os efeitos visuais. HeartBeatVFXData.Deactivate()
# Cancela o registro do agente de adereço do dispositivo de reprodução de áudio, fazendo com que o áudio do batimento cardíaco seja interrompido. SFXPlayer.Unregister(PropAgent)
# Reduz o contador de batimentos cardíacos. Esse contador nunca deve chegar a menos que 0. set NumberOfHeartBeats -= 1 if (NumberOfHeartBeats < 0) then set NumberOfHeartBeats = 0
# Limpa todos os efeitos visuais e sonoros de batimentos cardíacos de todos os agentes de adereços. DisableAll():void = Logger.Print("Desabilitando todos os batimentos cardíacos.")
# Itera por todos os efeitos visuais e move-os para 0,0,0. for (HeartBeatVFXDevice : AgentVFX): HeartBeatVFXDevice.Deactivate()
# Cancela o registro de todos os jogadores do áudio do batimento cardíaco. SFXPlayer.UnregisterAll()
# Reinicializa o contador de batimentos cardíacos para 0. set NumberOfHeartBeats = 0
A classe "heartbeat_warning_ui" contém uma estrutura de dados para rastrear a tela de IU e text_block por jogador, além da função para criar uma nova tela de IU de aviso de batimento cardíaco.
heartbeat_warning_ui := class: var Canvas:canvas = canvas{} var Text:text_block = text_block{}
# Cria a tela de IU para a mensagem de aviso. CreateCanvas():void = set Text = text_block{DefaultTextColor := NamedColors.White, DefaultShadowColor := NamedColors.Black} set Canvas = canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := vector2{X := 0.5, Y := 0.75}, Maximum := vector2{X := 0.5, Y := 0.75}} Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0} Alignment := vector2{X := 0.5, Y := 1.0} SizeToContent := true Widget := Text
A classe "heartbeat_vfx" contém uma estrutura de dados para rastrear os objetos de "vfx_spawner_device" por jogador, além das funções para definir o efeito visual para uma posição e redefini-lo.
heartbeat_vfx := class
@editável # O dispositivo de efeitos visuais para cada batimento cardíaco. VFXDevice:vfx_spawner_device = vfx_spawner_device{}
# Essas linhas são usadas para posicionar o batimento cardíaco acima da cabeça do agente de adereço. HeartBeatVFXOffset:vector3 = vector3{X := 0.0, Y := 0.0, Z := 110.0}
# Define a posição do efeito visual de batimento cardíaco e depois habilitar o efeito visual. Activate(Transform:transform):void = VFXPosition := Transform.Translation + HeartBeatVFXOffset if (VFXDevice.TeleportTo[VFXPosition, Transform.Rotation]): VFXDevice.Enable()
# Desabilita os efeitos visuais, ocultando os visuais de batimentos cardíacos. Deactivate():void = VFXDevice.Disable() ~~~
base_team.verse
~~~(verse) using { /Fortnite.com/Characters } using { /Fortnite.com/Devices } using { /Fortnite.com/UI } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath } using { /UnrealEngine.com/Temporary/UI } using { /Verse.org/Colors } using { /Verse.org/Simulation }
log_team := class(log_channel){}
Esta classe define os dispositivos necessários para as diferentes equipes da experiência.
Esta classe é abstrata, portanto não pode ser usada sozinha. Deve ser herdada por outra classe.
base_team := class
@editável # Usado para definir um jogador para a equipe. ClassSelector:class_and_team_selector_device = class_and_team_selector_device{}
@editável # Usado para atribuir pontuação aos agentes da equipe. ScoreManager:score_manager_device = score_manager_device{}
@editável # Usado para exibir o título da tarefa da equipe. TeamTitle:hud_message_device = hud_message_device{}
@editável # Usado para exibir a descrição da tarefa da equipe. TeamDescription:hud_message_device = hud_message_device{}
@editável # Usado para assinar eventos de membros da equipe (equipe de adereço) ou inimigos (equipe de caçadores) eliminados. TeamManager:team_settings_and_inventory_device = team_settings_and_inventory_device{}
# Esta é uma matriz de agentes da equipe.
var TeamAgents
# Este evento é sinalizado quando a matriz TeamAgents fica vazia (sinalizando o fim da rodada). TeamEmptyEvent:event() = event(){}
# Retorna a matriz TeamAgents atual.
# Este elemento é necessário porque a matriz TeamAgents é privada, portanto, outras classes não podem acessá-la diretamente.
GetAgents()
# Retorna o tamanho da matriz TeamAgents.
# Este elemento requer uma função, porque a matriz TeamAgents é privada, portanto, outras classes não podem acessá-la diretamente.
Count()
# Retorna um índice na matriz TeamAgents de um agente, caso contrário, falhará.
FindOnTeam(Agent:agent)
# Defina o agente na equipe e notifique o jogador. InitializeAgent(Agent:agent):void = AddAgentToTeam(Agent) ClassSelector.ChangeTeamAndClass(Agent) DisplayTeamInformation(Agent)
# Adicione um agente a TeamAgents. AddAgentToTeam(AgentToAdd:agent):void = if (not FindOnTeam[AgentToAdd]): Logger.Print("Adicionando agente à equipe.") set TeamAgents += array{AgentToAdd}
# Ativa os dispositivos de mensagens do HUD para mostrar ao jogador em qual equipe está. DisplayTeamInformation(Agent:agent):void = TeamTitle.Show(Agent) TeamDescription.Show(Agent)
# Quando um agente sair da partida, remova-o da matriz TeamAgents e verifique o final da rodada.
EliminateAgent(Agent:agent)
# Remove um agente de TeamAgents.
# Se o agente removido tiver sido o último, sinalize TeamEmptyEvent. RemoveAgentFromTeam(AgentToRemove:agent):void = set TeamAgents = TeamAgents.RemoveAllElements(AgentToRemove) Logger.Print("{Count()} agente(s) restante(s) na equipe.") if (Count() < 1): Logger.Print("Nenhum agente restante na equipe. Encerrando a rodada.") TeamEmptyEvent.Signal()
## hunter_team.verse
~~~(verse)
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Simulation }
# Herdando da classe base_team; a classe hunter_team contém as definições de dispositivos e funções relacionadas à equipe de caçadores e seus agentes.
hunter_team := class<concrete>(base_team):
@editável # Um agente caçador é criado a cada rodada para cada n jogadores. Exemplo: "HunterTeamPerNumberOfPlayers = 5.0" é 1 por 5 jogadores. Se o número de jogadores for 6, são criados 2 agentes caçadores.
HunterAgentPerNumberOfPlayers:float = 5.0 # Um mínimo de 1.1 é aplicado para garantir que pelo menos 1 agente de adereço seja criado.
@editável # O tempo em segundos antes que os agentes caçadores sejam gerados, dando aos agentes de adereços uma vantagem para serem ocultados.
SpawnDelay:float = 15.0
@editável # O máximo de pontos base que um agente caçador recebe por eliminar um agente de adereço. Esses pontos são divididos pelo número de agentes de adereços restantes.
MaxEliminationScore:int = 5000
@editável # O dispositivo cronômetro é usado para dar aos adereços um período de tolerância para serem ocultados.
WaitTimer:timer_device = timer_device{}
# Defina o agente como um agente caçador.
InitializeAgent<override>(NewHunterAgent:agent):void =
Logger.Print("Definindo um novo agente caçador.")
(super:)InitializeAgent(NewHunterAgent)
# Quando um agente caçador sair da partida, remova-o da matriz HunterAgents e verifique quanto ao final da rodada.
# Observe que estamos substituindo esta função porque não precisamos aprovar dados extras aqui como fazemos para a equipe de adereços.
EliminateAgent<override>(HunterAgent:agent)<suspends>:void =
Logger.Print("Agente caçador eliminado.")
(super:)EliminateAgent(HunterAgent)
prop_team.verse
~~~(verse) using { /Fortnite.com/Characters } using { /Fortnite.com/Devices } using { /Fortnite.com/UI } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath } using { /UnrealEngine.com/Temporary/UI } using { /Verse.org/Colors } using { /Verse.org/Simulation }
Esta mensagem é usada para imprimir o número de adereços restantes para todos os jogadores durante uma rodada.
PropAgentsRemainingMessage
Herdada da classe base_team, a classe prop_team contém definições de dispositivos e funções relacionadas à equipe de adereços e seus agentes.
Notavelmente, o comportamento do batimento cardíaco de um agente de adereço pode ser encontrado nesta classe.
prop_team := class
@editável # A pontuação que um agente de adereço recebe por segundo. ScorePerSecond:int = 10
@editável # A distância mínima que um agente de adereço deve percorrer para zerar o cronômetro de batimento cardíaco. MinimumMoveDistance:float = 100.0
@editável # O dispositivo cronômetro usado para atribuir pontuação a um adereço. ScoreTimer:timer_device = timer_device{}
@editável # Este dispositivo rastreador é usado para exibir os adereços restantes na tela. PropsRemainingTracker:tracker_device = tracker_device{}
@editável # Obtenha as propriedades da classe heart_beat. HeartBeat:heart_beat = heart_beat{}
# Defina o agente como um agente de adereço e atribua uma IU de batimento cardíaco.
InitializeAgent
# Quando o PropScoreTimer for concluído, conceda pontos a todos os agentes de adereços. PropInstigator é necessário para a assinatura do evento, mas não é usado. OnPropsScore(PropInstigator:?agent):void = if (PropAgents := GetAgents[]): for (PropAgent : PropAgents): ScoreManager.Activate(PropAgent)
# Quando um agente de adereço for eliminado ou sair da partida, remova-o da matriz PropAgents e verifique quanto ao final da rodada.
# Observe que essa etapa não é obrigatória, porque estamos passando todos os jogadores para a função para atualizar a mensagem restante dos adereços.
EliminateAgent
#Atualiza o número restante de adereços. UpdatePropsRemainingTracker()
# Atualiza o valor do dispositivo rastreador mostrando o número de adereços restantes. UpdatePropsRemainingTracker():void = PropsRemainingTracker.SetValue(Count())
# Se o agente de adereço parar de se mover, então execute uma corrida ("race") para ver se ele se move além do valor de "MinimumMoveDistance", o cronômetro de batimento cardíaco termina ou o agente adereço é eliminado.
RunPropGameLoop(PropAgent:agent)
# Execute o loop para sempre por meio do comportamento do adereço até que o agente adereço seja eliminado ou que o jogador saia da sessão. race: PropAgent.AwaitNoLongerAProp() loop:
# Espere até que o agente de adereço se mova uma distância menor que a mínima, depois avance. PropAgent.AwaitStopMoving(MinimumMoveDistance)
# Até que o agente de adereço se mova além da distância mínima, faça uma contagem regressiva do batimento cardíaco e depois reproduza o batimento cardíaco indefinidamente. race: PropAgent.AwaitStartMoving(MinimumMoveDistance) block: CountdownTimer(PropAgent) PropAgent.StartHeartbeat() Sleep(0.0) # Quando a corrida terminar (o agente de adereço se mover), comece o loop novamente.
# Executar o loop até que o agente de adereço não faça mais parte da matriz PropAgents. A remoção acontece se o agente de adereço for eliminado e transformado em caçador ou se o jogador sair da sessão.
(PropAgent:agent).AwaitNoLongerAProp()
# Executa o loop até que o agente se mova uma distância menor que "MinimumDistance".
(PropAgent:agent).AwaitStopMoving(MinimumDistance:float)
# Obtenha a posição inicial do agente a partir do personagem do agente na cena. if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation loop: Sleep(0.0) # Obtenha a posição do agente na próxima marcação do jogo. NewPosition := Tracked.GetTransform().Translation
# Se a distância da nova posição em relação à posição inicial for menor que "MinimumDistance", o agente não se moveu e interrompemos o loop. if (Distance(StartPosition, NewPosition) < MinimumDistance): Logger.Print("O agente se moveu uma distância menor que a mínima.") break
# Caso contrário, redefinimos "StartPosition" para garantir que o jogador se mova da nova posição. else: set StartPosition = NewPosition
# Executa o loop até que o agente se mova uma distância maior que "MinimumDistance".
(PropAgent:agent).AwaitStartMoving(MinimumDistance:float)
# Obtenha a posição inicial do agente a partir do personagem do agente na cena. if (Tracked := PropAgent.GetFortCharacter[]): StartPosition:vector3 = Tracked.GetTransform().Translation loop: Sleep(0.0) # Obtenha a posição do agente na próxima marcação do jogo. NewPosition := Tracked.GetTransform().Translation
# Se a distância da nova posição em relação à posição inicial for maior ou igual a "MinimumDistance", o agente não se moveu e interrompemos o loop. if (Distance(StartPosition, NewPosition) >= MinimumDistance): Logger.Print("O agente se moveu uma distância maior ou igual à mínima.") break
# Atrasa até o momento de início de "HeartBeatWarningTime". Depois, faz a contagem regressiva de "HeartBeatWarningTime" e ativa o texto da contagem regressiva. Limpa o texto quando adiado.
CountdownTimer(PropAgent:agent)
# Uma função "defer" acontece quando a função é concluída ou cancelada, como por exemplo, se perder uma corrida.
# Então, nesse caso, o texto de aviso é limpo quando a contagem regressiva termina ou se o agente de adereço se move antes de a contagem regressiva terminar. defer: UIData.Text.SetText(HeartBeatWarningClear)
# Define o texto de aviso para o tempo restante, espera um segundo e, depois, reduz o tempo restante. Se a contagem regressiva termina, interrompe o loop. loop: Logger.Print("Batimento cardíaco em {WarningTimeRemaining} segundo(s).") UIData.Text.SetText(HeartBeatWarningMessage(WarningTimeRemaining)) Sleep(1.0) set WarningTimeRemaining -= 1 if (WarningTimeRemaining <= 0): break else: Logger.Print("UIData não encontrado.")
# Ativa os efeitos visuais e sonoros do batimento cardíaco. Aguarda infinitamente até ser adiado e desabilita os efeitos visuais e sonoros do batimento cardíaco.
(PropAgent:agent).StartHeartbeat()
# Salve os dados de batimento cardíaco para que possamos passá-los em "defer" mais tarde, após PropAgent ser destruído ou sair do jogo. var HeartBeatVFXData:heartbeat_vfx = heartbeat_vfx{} if:
# Obtenha o índice do agente de adereço na matriz PropAgents para acessar o ator de efeitos visuais de batimento cardíaco correspondente. Index := FindOnTeam[PropAgent] set HeartBeatVFXData = HeartBeat.AgentVFX[Index] then: HeartBeat.Enable(PropAgent, HeartBeatVFXData)
# Quando esta função é cancelada pelo movimento do agente de adereço, por eliminação ou pelo fato de o jogador sair da sessão, desabilite o batimento cardíaco. defer: HeartBeat.Disable(PropAgent, HeartBeatVFXData) Sleep(Inf) # Não interromper a suspensão até que a corrida termine.
## round_timer.verse
~~~(verse)
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Colors }
using { /Verse.org/Simulation }
log_round_timer_device := class(log_channel){}
# Um "int" que permite valores entre os intervalos especificados. Este tipo é exigido por player_ui_slot.ZOrder.
round_int_clamped := type{_X:int where 0 <= _X, _X <= 2147483647}
# Esta mensagem é usada para gerar o tempo restante antes do final de uma rodada.
TimeRemainingMessage<localizes>(Minutes:string, Seconds:string):message = "{Minutes}:{Seconds}"
<#
Esta classe contém toda a lógica para gerenciar o tempo de rodada e exibir o tempo na tela.
Você pode usar este dispositivo com round_settings_device para encerrar de fato a rodada.
Este dispositivo gerencia o tempo sem o uso de um cronômetro.
Para usar esta classe:
1) Adicione o arquivo ao seu projeto.
2) Compile o código Verse no menu de Verse na barra de ferramentas.
3) Arraste o dispositivo para sua ilha da pasta Conteúdo/Dispositivos do Modo Criativo da ilha no Navegador de Conteúdo.
4) Inclua a classe wait_for_more_players em outro script Verse com:
@editable
RoundTimer:round_timer = round_timer{}
5) Compile o código Verse no menu de Verse na barra de ferramentas.
6) Conecte o dispositivo que você criou na etapa 3 ao dispositivo Verse.
7) Inicie o cronômetro da rodada com o seguinte código Verse:
RoundTimer.Start().
8) Reinicie ou interrompa o cronômetro com as funções equivalentes.
9) Aguarde o cronômetro iniciar com:
RoundTimer.AwaitStart().
10) Espere o cronômetro chegar ao fim com:
RoundTimer.AwaitEnd().
Chame a função EndRound em round_settings_device para encerrar de fato a rodada do jogo.
#>
round_timer := class(creative_device):
Logger:log = log{Channel:=log_prop_hunt_device}
@editável # O tempo, em minutos, de duração de uma rodada.
RoundTimeInMinutes:float = 5.0
@editável # A posição horizontal e vertical da IU do cronômetro na tela. "X 0-1" é da esquerda para a direita e "Y 0-1" é de cima para baixo.
UIPosition:vector2 = vector2{X:= 0.98, Y:=0.13}
@editável # A posição horizontal e vertical da IU do cronômetro na tela. "X 0-1" é da esquerda para a direita e "Y 0-1" é de cima para baixo.
UIAlignment:vector2 = vector2{X := 1.0, Y := 0.0}
@editável # ZOrder da IU em comparação com outros elementos da IU.
UIZOrder:round_int_clamped = 4
# Sinalizado quando a rodada foi iniciada.
RoundStarted:event() = event(){}
# Sinalizado quando a rodada está prestes a terminar.
RoundEndedEvent:event() = event(){}
# Este mapa associa uma caixa de texto para exibir o tempo para cada jogador.
var TimeRemainingTextBlocks:[player]text_block = map{}
# O tempo restante antes da conclusão da rodada, como um número inteiro.
var TimeRemainingInSeconds:int = 0
# Aguarda até que o cronômetro da rodada seja iniciado.
AwaitStart()<suspends>:void =
RoundStarted.Await()
Logger.Print("Cronômetro da rodada iniciado.")
# Usado para iniciar o cronômetro da rodada.
Start():void =
Logger.Print("Iniciando cronômetro da rodada.")
RoundStarted.Signal()
set TimeRemainingInSeconds = GetRoundTimeInSeconds()
spawn{ Running() }
#Reinicia o cronômetro para RoundTime.
Restart():void =
Logger.Print("Reiniciando cronômetro da rodada.")
set TimeRemainingInSeconds = GetRoundTimeInSeconds()
# Executa a lógica do cronômetro.
Running()<suspends>:void =
Logger.Print("Cronômetro da rodada em execução.")
loop:
UpdateTimeUI()
Sleep(1.0)
# Diminua TimeRemaining em 1 segundo e verifique se o tempo acabou. Se sim, encerre a rodada.
set TimeRemainingInSeconds -= 1
if (TimeRemainingInSeconds < 0):
Stop()
break
# Interrompe o cronômetro e encerra a rodada.
Stop():void =
Logger.Print("Encerrando cronômetro da rodada.")
# Pegamos um jogador entre os jogadores restantes na cena para encerrar a rodada.
Players:[]player = GetPlayspace().GetPlayers()
if (Instigator := Players[0]):
RoundEndedEvent.Signal()
# Espera até que o cronômetro da rodada esteja prestes a terminar.
AwaitEnd()<suspends>:void =
RoundEndedEvent.Await()
Logger.Print("Cronômetro da rodada encerrado.")
# Aceita um valor de tempo em minutos e retorna o valor em segundos.
GetRoundTimeInSeconds():int =
var InSeconds:int = 0
if (set InSeconds = Round[RoundTimeInMinutes * 60.0]) {}
InSeconds
# Quando o cronômetro chegar ao fim, atualiza o tempo restante e verifica se o tempo expirou.
UpdateTimeUI():void =
# Defina "Minutes" como TimeRemainingInSeconds/60 sem o restante.
var Minutes:int = 0
if (set Minutes = Floor(TimeRemainingInSeconds / 60)) {}
# Defina "Seconds" como o restante de TimeRemainingInSeconds/60.
var Seconds:int = 0
if (set Seconds = Mod[TimeRemainingInSeconds, 60]) {}
# Converta "Minutes" e "Seconds" em strings.
MinutesAsString := string("{Minutes}")
# Se "Seconds" for maior que 10, então precisamos adicionar um 0 na frente do valor para que ele seja exibido como ":0#" em vez de ":#".
SecondsAsString := if (Seconds < 10) then Join(array{string("{0}"),string("{Seconds}")},string()) else string("{Seconds}")
# Itere por todos os jogadores, verifique se eles têm TimeRemainingTextBlock, caso contrário, forneça um a eles. Em seguida, atualize o texto.
Players:[]player = GetPlayspace().GetPlayers()
for (Player : Players):
var TextBlock:text_block = text_block{}
if (set TextBlock = TimeRemainingTextBlocks[Player]) {}
else:
set TextBlock = SetUpTimeRemainingUI(Player)
TextBlock.SetText(TimeRemainingMessage(MinutesAsString, SecondsAsString))
# Aceita um jogador e, em seguida, adiciona uma tela de IU de tempo de rodada à tela e armazena TimeRemainingTextBlock para atualização posterior.
SetUpTimeRemainingUI(Player:player):text_block =
Logger.Print("Adicionando IU do cronômetro da rodada a um jogador.")
# Este é o text_block que gera o texto do tempo restante na tela.
TextBlock:text_block = text_block:
DefaultTextColor := NamedColors.White
DefaultShadowColor := NamedColors.Black
if (PlayerUI := GetPlayerUI[Player]):
if (set TimeRemainingTextBlocks[Player] = TextBlock) {}
# Esta é a tela que contém e posiciona o text_block na tela.
Canvas := canvas:
Slots := array:
canvas_slot:
Anchors := anchors{Minimum := UIPosition, Maximum := UIPosition}
Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
Alignment := UIAlignment
SizeToContent := true
Widget := TextBlock
# A tela é atribuída ao jogador.
PlayerUI.AddWidget(Canvas, player_ui_slot{ZOrder := UIZOrder})
# O text_block é retornado para que possa ser salvo no mapa e atualizado posteriormente conforme o tempo passa.
return TextBlock
waiting_for_more_players.verse
~~~(verse) using { /Fortnite.com/Devices } using { /Fortnite.com/UI } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath } using { /UnrealEngine.com/Temporary/UI } using { /Verse.org/Colors } using { /Verse.org/Simulation }
log_waiting_for_more_players_device := class(log_channel){}
Um "int" que permite valores entre os intervalos especificados. Este tipo é exigido por player_ui_slot.ZOrder.
waiting_int_clamped := type{_X:int where 0 <= _X, _X <= 2147483647}
Esta mensagem é usada para gerar o número de jogadores necessários antes que uma rodada possa começar.
WaitingForMorePlayersMessage
Esta classe serve para mostrar quantos jogadores são necessários para iniciar a rodada.
waiting_for_more_players_ui := class: var Canvas:canvas var TextBlock:text_block <# Esta classe contém toda a lógica para definir um número mínimo de jogadores e verificar se há jogadores suficientes para iniciar a rodada. Para usar esta classe: 1) Adicione o arquivo ao seu projeto.
2) Compile o código Verse no menu de Verse na barra de ferramentas.
3) Arraste o dispositivo para sua ilha da pasta Conteúdo/Dispositivos do Modo Criativo da ilha no Navegador de Conteúdo.
4) Conecte um dispositivo Temporizador à propriedade "WaitingForMorePlayersTimer" deste dispositivo.
5) Inclua a classe wait_for_more_players em outro script Verse com: @editable WaitingForMorePlayers:waiting_for_more_players = waiting_for_more_players{}
6) Compile o código Verse no menu de Verse na barra de ferramentas.
7) Conecte o dispositivo que você criou na etapa 3 ao dispositivo e propriedade Verse exposto na etapa 6.
8) Aguarde a função CheckForMinimumNumberOfPlayers passando-a para um jogador. Por exemplo: Players = GetPlayspace().GetPlayers() CheckForMinimumNumberOfPlayers(Players)
9) Em IslandSettings, defina a contagem regressiva de início do jogo para 0.0.
>
waiting_for_more_players := class(creative_device): Logger:log = log{Channel:=log_waiting_for_more_players_device}
@editável # O número mínimo de jogadores necessários na partida para que uma rodada comece. MinimumNumberOfPlayers:int = 2
@editável # A posição horizontal e vertical da IU do cronômetro na tela. "X 0-1" é da esquerda para a direita e "Y 0-1" é de cima para baixo. UIPosition:vector2 = vector2{X:= 0.5, Y:=0.4}
@editável # A posição horizontal e vertical da IU do cronômetro na tela. "X 0-1" é da esquerda para a direita e "Y 0-1" é de cima para baixo. UIAlignment:vector2 = vector2{X := 0.5, Y := 0.5}
@editável # ZOrder da IU em comparação com outros elementos da IU. UIZOrder:waiting_int_clamped = 3
@editável # Este cronômetro é usado para fazer a contagem regressiva até o início da rodada depois de esperar que os jogadores entrem na partida. WaitingForMorePlayersTimer:timer_device = timer_device{}
# Este mapa associa uma tela de IU para exibir o número de jogadores necessários para iniciar uma rodada para cada jogador. var WaitingForMorePlayersUI:[player]?waiting_for_more_players_ui = map{}
#Verifica se há jogadores suficientes para iniciar a rodada. Caso contrário, esperar até que o número de jogadores seja maior ou igual a MaximumNumberOfPlayers.
WaitForMinimumNumberOfPlayers(Players:[]player)
# Exibe uma mensagem de IU "Aguardando mais jogadores" para cada jogador, caso ainda não tiverem recebido uma. Atualiza o contador de jogadores para todos os jogadores. DisplayWaitingForMorePlayers(Players:[]player):void = PlayersNeededCount := MinimumNumberOfPlayers - Players.Length Logger.Print("{Players.Length} jogadores na rodada, aguardando a entrada de mais {PlayersNeededCount} jogador(es).") for (Player : Players):
# Se o jogador tiver WaitingForMorePlayersUI, obtenha o TextBlock e atualize o texto para mostrar o número correto de jogadores necessários para iniciar a rodada. if (UIData := WaitingForMorePlayersUI[Player]?): UIData.TextBlock.SetText(WaitingForMorePlayersMessage(PlayersNeededCount)) # Caso contrário, crie um WaitingForMorePlayersUI para o jogador. else: SetUpWaitingForMorePlayersUI(Player, PlayersNeededCount)
# Aceita um jogador e player_ui e adiciona uma tela de IU "Aguardando mais jogadores" em sua tela. SetUpWaitingForMorePlayersUI(Player:player, PlayersNeededCount:int):void = Logger.Print("Criando UI 'aguardando mais jogadores'.") if (PlayerUI := GetPlayerUI[Player]): # Este é o text_block que gera o texto na tela dizendo que aguarda mais jogadores. TextBlock:text_block = text_block: DefaultText := WaitingForMorePlayersMessage(PlayersNeededCount) DefaultTextColor := NamedColors.White DefaultShadowColor := NamedColors.Black
# Esta é a tela que contém e posiciona o text_block na tela. Canvas := canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := UIPosition, Maximum := UIPosition} Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0} Alignment := UIAlignment SizeToContent := true Widget := TextBlock # A tela é atribuída ao jogador. PlayerUI.AddWidget(Canvas, player_ui_slot{ZOrder := UIZOrder}) # O text_block é salvo no mapa para que possamos atualizar o texto mais tarde, à medida que mais jogadores entrarem no jogo. if (set WaitingForMorePlayersUI[Player] = option{ waiting_for_more_players_ui{Canvas := Canvas, TextBlock := TextBlock} }) {}
# Remove a mensagem da IU "Aguardando mais jogadores" para cada jogador que tiver uma. ClearWaitingForMorePlayers():void = Logger.Print("Excluindo a mensagem 'Aguardando mais jogadores' da IU.") for (Player -> UIData : WaitingForMorePlayersUI): if: PlayerUI := GetPlayerUI[Player] Canvas := UIData?.Canvas set WaitingForMorePlayersUI[Player] = false then: PlayerUI.RemoveWidget(Canvas) ~~~