Código completo
A seguir está o código completo para um jogo de infiltração de três equipes que distribui os jogadores de maneira assimétrica para criar experiências de jogo dinâmicas.
triad_infiltration_game.verse
~~~(verse) using { /Fortnite.com/Devices } using { /Fortnite.com/FortPlayerUtilities } using { /Verse.org/Simulation } using { /Verse.org/Random } using { /UnrealEngine.com/Temporary/Diagnostics }
triad_infiltration_log_channel := class(log_channel){}
triad_infiltration := class(creative_device):
Logger:log = log{Channel := triad_infiltration_log_channel}
# Para evitar que os jogadores não consigam entrar em uma equipe, você deve definir o número máximo # de jogadores nas configurações da ilha para a soma de todas as variáveis Maximum(Team).
# Número máximo de jogadores na equipe de infiltradores. @editable MaximumInfiltrators:int = 2
# Número máximo de jogadores na equipe de atacantes. @editable MaximumAttackers:int = 4
# Número máximo de jogadores na equipe de defensores. @editable MaximumDefenders:int = 4
# A matriz de teletransportadores que teletransportam os jogadores até a plataforma de surgimento de suas respectivas equipes assim que o jogo começa. @editable Teleporters:[]teleporter_device = array{}
# A referência ao script invisibility_manager, que controla a invisibilidade do infiltrador.
@editable
InvisibilityManager:invisibility_manager = invisibility_manager{}
# A matriz de distribuidores de armas para cada equipe. @editable var WeaponGranters:[]item_granter_device = array{}
# A matriz de geradores de jogadores de cada equipe. @editable PlayersSpawners:[]player_spawner_device = array{}
# A referência à equipe de infiltradores. var MaybeInfiltrators:?team = false
# A referência à equipe de atacantes. var MaybeAttackers:?team = false
# A referência à equipe de defensores. var MaybeDefenders:?team = false
# A matriz de todas as equipes do jogo. var AllTeams:[]team = array{}
# O mapa das equipes para seu número máximo de jogadores. var TeamsAndTotals:[team]int = map{}
OnBegin
# Obter todas as equipes. set AllTeams = GetPlayspace().GetTeamCollection().GetTeams() var AllPlayers:[]player = GetPlayspace().GetPlayers() # Salve as equipes para fazer referência a elas mais tarde. set MaybeInfiltrators = option{AllTeams[0]} set MaybeAttackers = option{AllTeams[1]} set MaybeDefenders = option{AllTeams[2]}
if: Infiltrators := MaybeInfiltrators? Attackers := MaybeAttackers? Defenders := MaybeDefenders? Logger.Print("As três equipes foram encontradas") set TeamsAndTotals[Infiltrators] = MaximumInfiltrators set TeamsAndTotals[Attackers] = MaximumAttackers set TeamsAndTotals[Defenders] = MaximumDefenders Logger.Print("Coloque as três equipes em TeamsAndTotals") then: #Assine PlayerAddedEvent para permitir o reequilíbrio da equipe quando um novo jogador entrar no jogo. GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded) for(PlayerSpawner:PlayersSpawners): PlayerSpawner.SpawnedEvent.Subscribe(OnPlayerSpawn)
BalanceTeams() Logger.Print("Equipes equilibradas, chamando script de invisibilidade") InvisibilityManager.StartInvisibilityManager(AllTeams, AllPlayers, Infiltrators) Sleep(0.25) TeleportPlayersToStartLocations() else: Logger.Print("Não foi possível encontrar todas as equipes, certifique-se de atribuir as equipes corretas nas configurações da ilha.")
# Conceder uma arma aos jogadores com base no índice de suas equipes na matriz Teams, # fazendo a indexação na matriz WeaponGranters GrantTeamWeapon(InPlayer:player):void= if(CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[InPlayer]): for(TeamIndex -> PlayerTeam:AllTeams, PlayerTeam = CurrentTeam): if(WeaponGranter := WeaponGranters[TeamIndex]): WeaponGranter.GrantItem(InPlayer) Logger.Print("O jogador na equipe {TeamIndex + 1} recebeu uma arma")
# Executado quando qualquer jogador surge de uma plataforma de surgimento # Chama GrantTeamWeapon usando o SpawnedAgent fornecido OnPlayerSpawn(SpawnedAgent:agent):void= if(SpawnedPlayer := player[SpawnedAgent]): Logger.Print("Tentando conceder uma arma ao jogador que surgiu") GrantTeamWeapon(SpawnedPlayer)
# Lida com a entrada de um novo jogador no jogo. OnPlayerAdded(InPlayer:player):void= Logger.Print("Um novo jogador entrou. Atribuindo-o a uma equipe.") FortTeamCollection := GetPlayspace().GetTeamCollection()
# Atribuir o novo jogador à menor equipe, de forma assimétrica. BalancePlayer(InPlayer)
for: TeamIndex -> PlayerTeam:AllTeams PlayerTeam = FortTeamCollection.GetTeam[InPlayer] TeamTeleporter := Teleporters[TeamIndex] Transform := TeamTeleporter.GetTransform() do: InPlayer.Respawn(Transform.Translation, Transform.Rotation) Logger.Print("Teletransportou o jogador gerado para seu local inicial") # Se o jogador era um infiltrador, chamar OnInfiltratorJoined em # InvisibilityManager. if(PlayerTeam = MaybeInfiltrators?): InvisibilityManager.OnInfiltratorJoined(InPlayer)
# Equilibra todos os jogadores de todas as equipes do jogo BalanceTeams():void= Logger.Print("Começando a distribuir as equipes") var AllPlayers:[]player := GetPlayspace().GetPlayers() set AllPlayers = Shuffle(AllPlayers) Logger.Print("O comprimento de AllPlayers é {AllPlayers.Length}")
for (TeamPlayer:AllPlayers): BalancePlayer(TeamPlayer)
# Para cada jogador, percorra a lista de equipes e atribua-as à # equipe com o menor número de jogadores ou à sua equipe titular em caso de empate. BalancePlayer(InPlayer:player):void= Logger.Print("Começando a equilibrar o jogador") var TeamToAssign:?team = false set TeamToAssign = FindTeamWithLargestDifference() if (AssignedTeam := TeamToAssign?, GetPlayspace().GetTeamCollection().AddToTeam[InPlayer, AssignedTeam]): Logger.Print("Jogador atribuído a uma nova equipe") else: Logger.Print("Este jogador já estava na menor equipe")
# Encontrar a equipe com a maior diferença no número de jogadores em comparação com seu # número máximo de jogadores. FindTeamWithLargestDifference():?team = Logger.Print("Tentativa de encontrar a menor equipe") var TeamToAssign:?team = false var LargestDifference:int = 0 for: CandidateTeamIndex -> CandidateTeam:AllTeams CurrentTeamSize := GetPlayspace().GetTeamCollection().GetAgents[CandidateTeam].Length MaximumTeamSize := TeamsAndTotals[CandidateTeam] do: Logger.Print("Verificando uma equipe...") Logger.Print("O tamanho máximo da equipe {CandidateTeamIndex + 1} é {MaximumTeamSize}") DifferenceFromMaximum := MaximumTeamSize - CurrentTeamSize Logger.Print("A diferença do máximo é {DifferenceFromMaximum}") if(LargestDifference < DifferenceFromMaximum): set LargestDifference = DifferenceFromMaximum set TeamToAssign = option{CandidateTeam} Logger.Print("Equipe encontrada {CandidateTeamIndex + 1} com diferença de {DifferenceFromMaximum}")
return TeamToAssign
# Teletransporta os jogadores até a plataforma de surgimento de suas respectivas equipes após o término do equilíbrio de equipes. TeleportPlayersToStartLocations():void= Logger.Print("Teletransportando jogadores para locais iniciais") for: TeamIndex -> PlayerTeam:AllTeams TeamPlayers := GetPlayspace().GetTeamCollection().GetAgents[PlayerTeam] TeamTeleporter := Teleporters[TeamIndex] do: for(TeamPlayer:TeamPlayers): TeamTeleporter.Teleport(TeamPlayer) Logger.Print("Teletransportou este jogador para o local inicial")
### invisibility.verse
~~~(verse)
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
triad_invisibility_log_channel := class(log_channel){}
invisibility_manager := class(creative_device):
Logger:log = log{Channel := triad_invisibility_log_channel}
# A matriz de geradores de jogadores para a equipe de infiltradores
@editable
PlayersSpawners:[]player_spawner_device = array{}
# Se a visibilidade dos infiltradores é ou não compartilhada com colegas de equipe
@editable
IsVisibilityShared:logic = true
# Por quanto tempo os infiltradores ficam visíveis depois de receberem dano
@editable
VulnerableSeconds:float = 3.0
# A rapidez com que os infiltradores cintilam depois de receberem dano.
@editable
FlickerRateSeconds:float = 0.4
# A matriz de todas as equipes do jogo.
var AllTeams:[]team = array{}
# O mapa de jogadores para a quantidade de segundos restantes para eles continuarem cintilando.
var PlayerVisibilitySeconds:[agent]float = map{}
OnBegin<override>()<suspends>:void=
# Esperar que as equipes se distribuam antes de assinar eventos que tornem os jogadores invisíveis
Logger.Print("Aguardando a distribuição das equipes...")
# Inicia a lógica do gerenciador de invisibilidade. Chamada da classe triad_infiltration após o término do equilíbrio de equipes
StartInvisibilityManager<public>(GameTeams:[]team, AllPlayers:[]player, Infiltrators:team):void=
Logger.Print("Script de invisibilidade iniciado!")
set AllTeams = GameTeams
for(PlayerSpawner:PlayersSpawners):
PlayerSpawner.SpawnedEvent.Subscribe(OnPlayerSpawn)
# Se os jogadores surgirem na equipe de infiltradores, gerar uma função OnInfiltratorDamaged para cada
# um. Em seguida, tornar seu personagem invisível.
for(TeamPlayer:AllPlayers):
if:
FortCharacter:fort_character = TeamPlayer.GetFortCharacter[]
CurrentTeam:team := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]
Logger.Print("Obteve a equipe atual deste jogador")
Infiltrators = CurrentTeam
set PlayerVisibilitySeconds[TeamPlayer] = 0.0
Logger.Print("Jogador adicionado a PlayerVisibilitySeconds")
then:
spawn{OnInfiltratorDamaged(TeamPlayer)}
Logger.Print("Jogador surgiu como um infiltrador, deixando-o invisível")
FortCharacter.Hide()
else:
Logger.Print("Este jogador não é um infiltrador")
# Cintila para avisar a visibilidade de um agente, ocultando e mostrando repetidamente seu fort_character
FlickerCharacter(InCharacter:fort_character)<suspends>:void=
Logger.Print("FlickerCharacter() invocado")
# Loop escondendo e mostrando o personagem para criar um efeito de cintilação.
loop:
InCharacter.Hide()
Sleep(FlickerRateSeconds)
InCharacter.Show()
Sleep(FlickerRateSeconds)
# A cada loop, diminuor a quantidade de tempo que o personagem pisca em FlickerRateSeconds.
# Se o tempo restante atingir 0, sair do loop
if:
TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2
TimeRemaining <= 0.0
then:
InCharacter.Hide()
break
# Cintila para avisar a visibilidade de um agente sempre que ele recebe dano
OnInfiltratorDamaged(InAgent:agent)<suspends>:void=
Logger.Print("Tentativa de iniciar cintilação desse personagem")
TeamCollection := GetPlayspace().GetTeamCollection()
if (FortCharacter := InAgent.GetFortCharacter[]):
loop:
if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]):
# Para cada colega de equipe, defina-os em segundos de PlayerVisibility e gere um FlickerEvent.
for(Teammate:TeamAgents):
Logger.Print("Chamando StartOrResetFlickering em um colega de equipe")
StartOrResetFlickering(Teammate)
else:
# Apenas cintilar o personagem que recebeu dano.
Logger.Print("Calling StartOrResetFlickering on InAgent")
StartOrResetFlickering(InAgent)
FortCharacter.DamagedEvent().Await()
# Inicia um novo evento cintilador se o agente estiver invisível, caso contrário,
# redefine a cintilação contínua do agente.
StartOrResetFlickering(InAgent:agent):void=
if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]):
Logger.Print("Tentativa de iniciar NOVO FlickerEvent para este personagem")
# Nova cintilação iniciada.
if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds):
spawn{FlickerCharacter(FortCharacter)}
Logger.Print("FlickerEvent gerado para este personagem")
else:
# Redefinir cintilação contínua.
if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds):
Logger.Print("Redefinir o FlickerTimer do personagem para VulnerableSeconds")
# Retorna se o jogador ainda tem tempo restante para cintilar
IsFlickering(InAgent:agent)<decides><transacts>:void=
PlayerVisibilitySeconds[InAgent] > 0.0
# Gera uma função OnInfiltratorDamaged quando um novo infiltrador entra no jogo
OnInfiltratorJoined<public>(InAgent:agent):void=
spawn{OnInfiltratorDamaged(InAgent)}
# Lida com a geração de um jogador a partir de uma plataforma de surgimento de infiltradores
OnPlayerSpawn(SpawnedAgent:agent):void=
Logger.Print("Um jogador acabou de surgir de uma plataforma de surgimento de infiltradores!")
if:
FortCharacter:fort_character = SpawnedAgent.GetFortCharacter[]
CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[SpawnedAgent]
AllTeams[0] = CurrentTeam
Logger.Print("Jogador surgiu como um infiltrador, deixando-o invisível")
then:
FortCharacter.Hide()
~~~
### item_capture_manager.verse
~~~(verse)
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Fortnite.com/Characters }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
triad_item_capture_log_channel := class(log_channel){}
item_capture_manager := class(creative_device):
Logger:log = log{Channel := triad_item_capture_log_channel}
# O gerador de itens de captura que gera o item a ser capturado.
@editable
CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{}
# Adereço que flutua acima da cabeça dos jogadores quando eles estão segurando o item a partir de
# CaptureItemSpawner.
@editable
CaptureItemIndicator:creative_prop = creative_prop{}
# O indicador que mostra no mapa onde estão os objetivos de cada equipe.
@editable
MapIndicator:map_indicator_device = map_indicator_device{}
# Com que frequência CaptureItemIndicator atualiza sua posição.
@editable
UpdateRateSeconds:float = 0.15
# A que altura acima da cabeça do jogador CaptureItemIndicator flutua.
@editable
VerticalOffset:float = 180.0
Mostra uma mensagem quando um jogador coleta o item de captura.
@editable
ItemGrabbedMessageDevice:hud_message_device = hud_message_device{}
# O tempo de espera antes de retornar os indicadores CaptureItem e Map.
# Um tempo negativo indica que os indicadores nunca retornarão, a menos que o objetivo seja
# coletado novamente.
@editable
ReturnTime:float = 10.0
# Atribui uma pontuação a uma equipe sempre que um jogador coleta o objeto.
@editable
ScoreManagerDevice:score_manager_device = score_manager_device{}
OnBegin<override>()<suspends>:void=
CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp)
CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured)
CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped)
SpawnerTransform := CaptureItemSpawner.GetTransform()
# Teletransportar de volta ao gerador, ocultando CaptureItemIndicator abaixo do mapa fora do local.
CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)
MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)
Logger.Print("Sinalizador retornado para gerador de captura")
# Sinalizar cada jogador quando ele capturar o objetivo.
OnItemPickedUp(InAgent:agent):void=
Logger.Print("Objetivo capturado")
if(FortCharacter := InAgent.GetFortCharacter[]):
ItemGrabbedMessageDevice.Show()
spawn{FollowCharacter(FortCharacter)}
# Quando um jogador deixa um item cair, ele gerará uma função WaitForReturn()
# se ReturnTime for maior que 0.
OnItemDropped(InAgent:agent):void=
Logger.Print("Objetivo solto")
if(ReturnTime >= 0.0):
spawn{WaitForReturn()}
else:
Logger.Print("O objetivo solto não retorna")
# Quando o item for capturado, atribuir pontuação à equipe de captura e retornar os indicadores.
OnItemCaptured(CapturingAgent:agent):void=
Logger.Print("Objetivo capturado")
ScoreManagerDevice.Activate()
ReturnIndicators()
# Aguardar um período de tempo ReturnTime e retornar os indicadores.
WaitForReturn()<suspends>:void=
Logger.Print("Aguardando o retorno dos indicadores...")
# Retornar os indicadores CaptureItem e Map se o item de captura
# não for coletado antes de o tempo expirar.
ShouldReturn:logic := race:
block:
Sleep(ReturnTime)
true
block:
CaptureItemSpawner.ItemPickedUpEvent.Await()
false
if(ShouldReturn?):
ReturnIndicators()
# Faz com que CaptureItemIndicator siga continuamente um jogador acima de sua cabeça.
# Percorre entre o loop de atualização de CaptureItemIndictator e se o jogador
# captura ou solta o item ou é eliminado.
FollowCharacter(FortCharacter:fort_character)<suspends>:void=
Logger.Print("Função FollowCharacter gerada")
race:
loop:
Transform := FortCharacter.GetTransform()
spawn{CaptureItemIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)}
spawn{MapIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)}
# Como queremos garantir que esse loop seja executado apenas uma vez por atualização de simulação, colocamos para em suspensão durante um marca de jogo.
Sleep(0.0)
CaptureItemSpawner.ItemCapturedEvent.Await()
CaptureItemSpawner.ItemDroppedEvent.Await()
FortCharacter.EliminatedEvent().Await()
Logger.Print("Objetivo solto ou capturado")
# Retorna os indicadores de mapa e item de captura às suas posições iniciais acima dos geradores.
ReturnIndicators():void=
SpawnerTransform := CaptureItemSpawner.GetTransform()
# Teletransportar de volta ao gerador, ocultando CaptureItemIndicator e MapIndicator acima do mapa fora do local.
spawn{CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)}
spawn{MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)}
Logger.Print("Indicadores retornados ao gerador de captura")
Por conta própria
Tendo concluído este guia, você aprendeu a usar o Verse para criar um jogo que distribui equipes de jogadores de maneira assimétrica.
Usando o que aprendeu, tente fazer o seguinte:
- Tente jogar com parâmetros diferentes para infiltradores, atacantes e defensores, para criar sua experiência de jogo ideal. E se os infiltradores tivessem armas brancas? E se os defensores também fossem invisíveis?
- Os infiltradores e os atacantes podem lutar pelo mesmo objetivo? Você consegue mudar a condição de vitória?