Codice completo
Di seguito è riportato il codice completo di un gioco di infiltrazione a tre team che bilancia i giocatori in modo asimmetrico per creare un'esperienza di gioco dinamica.
triad_infiltration_game.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}
# Per evitare che i giocatori non siano in grado di unirsi a un team, dovresti impostare il numero massimo
# di giocatori nelle impostazioni isola rispetto alla somma di tutte le variabili Maximum(Team).
# Numero massimo di giocatori nel team degli infiltrati.
@editable
MaximumInfiltrators:int = 2
# Numero massimo di giocatori nel team degli attaccanti.
@editable
MaximumAttackers:int = 4
# Numero massimo di giocatori nel team dei difensori.
@editable
MaximumDefenders:int = 4
# Array di teletrasporti che teletrasportano i giocatori alla piattaforma di generazione del loro team una volta iniziato il gioco.
@editable
Teleporters:[]teleporter_device = array{}
# Riferimento allo script invisibility_manager che controlla l'invisibilità degli infiltrati.
@editable
InvisibilityManager:invisibility_manager = invisibility_manager{}
# Array di assegnatori di armi per ogni team.
@editable
var WeaponGranters:[]item_granter_device = array{}
# Array di generatori di giocatori per ogni team.
@editable
PlayersSpawners:[]player_spawner_device = array{}
# Riferimento al team degli infiltrati.
var MaybeInfiltrators:?team = false
# Riferimento al team degli attaccanti.
var MaybeAttackers:?team = false
# Riferimento al team dei difensori.
var MaybeDefenders:?team = false
# Array di tutti i team nel gioco.
var AllTeams:[]team = array{}
# Mappa dei team con il loro numero massimo di giocatori.
var TeamsAndTotals:[team]int = map{}
OnBegin<override>()<suspends>:void =
# Ottieni tutti i team.
set AllTeams = GetPlayspace().GetTeamCollection().GetTeams()
var AllPlayers:[]player = GetPlayspace().GetPlayers()
# Salva i team per farvi riferimento in seguito.
set MaybeInfiltrators = option{AllTeams[0]}
set MaybeAttackers = option{AllTeams[1]}
set MaybeDefenders = option{AllTeams[2]}
if:
Infiltrators := MaybeInfiltrators?
Attackers := MaybeAttackers?
Defenders := MaybeDefenders?
Logger.Print("Sono stati trovati tutti e tre i team")
set TeamsAndTotals[Infiltrators] = MaximumInfiltrators
set TeamsAndTotals[Attackers] = MaximumAttackers
set TeamsAndTotals[Defenders] = MaximumDefenders
Logger.Print("Configura tutti e tre i team in TeamsAndTotals")
then:
#Sottoscrivi l'evento PlayerAddedEvent per permettere il ribilanciamento del team quando un nuovo giocatore si unisce al gioco.
GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded)
for(PlayerSpawner:PlayersSpawners):
PlayerSpawner.SpawnedEvent.Subscribe(OnPlayerSpawn)
BalanceTeams()
Logger.Print("Team bilanciati correttamente: chiamata dello script di invisibilità")
InvisibilityManager.StartInvisibilityManager(AllTeams, AllPlayers, Infiltrators)
Sleep(0.25)
TeleportPlayersToStartLocations()
else:
Logger.Print("Impossibile trovare tutti i team: assicurati di assegnare i team corretti nelle impostazioni della tua isola.")
# Assegna un'arma ai giocatori in base all'indice del loro team nell'array Team
# indicizzando l'array 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("Arma assegnata a un giocatore del team {TeamIndex + 1}")
# Viene eseguito quando avviene la generazione di qualsiasi giocatore su una piattaforma di generazione.
# Chiama GrantTeamWeapon utilizzando lo SpawnedAgent fornito.
OnPlayerSpawn(SpawnedAgent:agent):void=
if(SpawnedPlayer := player[SpawnedAgent]):
Logger.Print("Tentativo di assegnare un'arma al giocatore generato")
GrantTeamWeapon(SpawnedPlayer)
# Gestisce un nuovo giocatore che si unisce al gioco.
OnPlayerAdded(InPlayer:player):void=
Logger.Print("Si è unito un nuovo giocatore, assegnazione a un team in corso")
FortTeamCollection := GetPlayspace().GetTeamCollection()
# Assegna il nuovo giocatore al team meno numeroso in modo asimmetrico.
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("Il giocatore generato è stato teletrasportato nella sua posizione iniziale")
# Se il giocatore era un infiltrato, chiama OnInfiltratorJoined in
# InvisibilityManager.
if(PlayerTeam = MaybeInfiltrators?):
InvisibilityManager.OnInfiltratorJoined(InPlayer)
# Bilancia equamente i giocatori di tutti i team presenti nel gioco
BalanceTeams():void=
Logger.Print("Avvio del bilanciamento dei team")
var AllPlayers:[]player := GetPlayspace().GetPlayers()
set AllPlayers = Shuffle(AllPlayers)
Logger.Print("La lunghezza di AllPlayers è {AllPlayers.Length}")
for (TeamPlayer:AllPlayers):
BalancePlayer(TeamPlayer)
# Per ogni giocatore, scorri l'elenco dei team e assegnalo al
# team con il minor numero di giocatori o il team iniziale in caso di parità.
BalancePlayer(InPlayer:player):void=
Logger.Print("Avvio del bilanciamento dei giocatori")
var TeamToAssign:?team = false
set TeamToAssign = FindTeamWithLargestDifference()
if (AssignedTeam := TeamToAssign?, GetPlayspace().GetTeamCollection().AddToTeam[InPlayer, AssignedTeam]):
Logger.Print("Giocatore assegnato a un nuovo team")
else:
Logger.Print("Il giocatore era già membro del team meno numeroso")
# Trova il team con la maggior differenza nel rispettivo numero di giocatori rispetto a
# numero massimo di giocatori.
FindTeamWithLargestDifference():?team =
Logger.Print("Tentativo di trovare il team meno numeroso")
var TeamToAssign:?team = false
var LargestDifference:int = 0
for:
CandidateTeamIndex -> CandidateTeam:AllTeams
CurrentTeamSize := GetPlayspace().GetTeamCollection().GetAgents[CandidateTeam].Length
MaximumTeamSize := TeamsAndTotals[CandidateTeam]
do:
Logger.Print("Controllo del team in corso...")
Logger.Print("Le dimensioni massime del team {CandidateTeamIndex + 1} sono {MaximumTeamSize}")
DifferenceFromMaximum := MaximumTeamSize - CurrentTeamSize
Logger.Print("La differenza dal valore massimo è {DifferenceFromMaximum}")
if(LargestDifference < DifferenceFromMaximum):
set LargestDifference = DifferenceFromMaximum
set TeamToAssign = option{CandidateTeam}
Logger.Print("Trovato team {CandidateTeamIndex + 1} con una differenza di giocatori di {DifferenceFromMaximum}")
return TeamToAssign
# Teletrasporta i giocatori nella zona di generazione prevista per il loro team una volta terminato il bilanciamento dei team.
TeleportPlayersToStartLocations():void=
Logger.Print("Teletrasporto dei giocatori alle posizioni di partenza")
for:
TeamIndex -> PlayerTeam:AllTeams
TeamPlayers := GetPlayspace().GetTeamCollection().GetAgents[PlayerTeam]
TeamTeleporter := Teleporters[TeamIndex]
do:
for(TeamPlayer:TeamPlayers):
TeamTeleporter.Teleport(TeamPlayer)
Logger.Print("Il giocatore è stato teletrasportato nella sua posizione iniziale")
invisibility.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}
# Array di generatori di giocatori per il team degli infiltrati
@editable
PlayersSpawners:[]player_spawner_device = array{}
# Determina se la visibilità degli infiltrati è condivisa con i compagni di team.
@editable
IsVisibilityShared:logic = true
# Per quanto tempo gli infiltrati sono visibili dopo aver subito danni.
@editable
VulnerableSeconds:float = 3.0
# Quanto velocemente gli infiltrati sfarfallano dopo essere stati danneggiati.
@editable
FlickerRateSeconds:float = 0.4
# Array di tutti i team nel gioco.
var AllTeams:[]team = array{}
# Mappa dei giocatori in funzione del numero di secondi che hanno a disposizione per continuare a lampeggiare.
var PlayerVisibilitySeconds:[agent]float = map{}
OnBegin<override>()<suspends>:void=
# Attendi che i team siano bilanciati prima di iscriverti agli eventi che rendono invisibili i giocatori.
Logger.Print("In attesa del bilanciamento dei team...")
# Avvia la logica del gestore dell'invisibilità. Chiamato dalla classe triad_infiltration una volta terminato il bilanciamento dei team
StartInvisibilityManager<public>(GameTeams:[]team, AllPlayers:[]player, Infiltrators:team):void=
Logger.Print("Script di invisibilità avviato!")
set AllTeams = GameTeams
for(PlayerSpawner:PlayersSpawners):
PlayerSpawner.SpawnedEvent.Subscribe(OnPlayerSpawn)
# Per ogni giocatore, se si è generato nel team degli infiltrati, genera una funzione OnInfiltratorDamaged per quel
# giocatore. Poi rendi il loro personaggio invisibile.
for(TeamPlayer:AllPlayers):
if:
FortCharacter:fort_character = TeamPlayer.GetFortCharacter[]
CurrentTeam:team := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]
Logger.Print("Team attuale del giocatore identificato")
Infiltrators = CurrentTeam
set PlayerVisibilitySeconds[TeamPlayer] = 0.0
Logger.Print("Giocatore aggiunto a PlayerVisibilitySeconds")
then:
spawn{OnInfiltratorDamaged(TeamPlayer)}
Logger.Print("Giocatore generato come infiltrato, rendendolo invisibile")
FortCharacter.Hide()
else:
Logger.Print("Questo giocatore non è un infiltrato"))
# Applica un effetto di sfarfallio alla visibilità di un agente, nascondendo e mostrando in modo ripetuto il suo fort_character
FlickerCharacter(InCharacter:fort_character)<suspends>:void=
Logger.Print("FlickerCharacter() invocato")
# Nascondi e mostra in loop il personaggio per creare un effetto di sfarfallio.
loop:
InCharacter.Hide()
Sleep(FlickerRateSeconds)
InCharacter.Show()
Sleep(FlickerRateSeconds)
# Ad ogni loop, diminuisci la quantità di tempo in cui il personaggio sfarfalla di FlickerRateSeconds.
# Se il tempo rimanente raggiunge lo 0, interrompi il loop.
if:
TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2
TimeRemaining <= 0.0
then:
InCharacter.Hide()
break
# Applica un effetto di sfarfallio alla visibilità di un agente ogni volta che subisce danni
OnInfiltratorDamaged(InAgent:agent)<suspends>:void=
Logger.Print("Tentativo di attivare l'effetto di sfarfallio per questo personaggio")
TeamCollection := GetPlayspace().GetTeamCollection()
if (FortCharacter := InAgent.GetFortCharacter[]):
loop:
if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]):
# Per ogni compagno di team, imposta i secondi di PlayerVisibility e genera un FlickerEvent.
for(Teammate:TeamAgents):
Logger.Print("Chiamata di StartOrResetFlickering su un compagno di team")
StartOrResetFlickering(Teammate)
else:
# Applica l'effetto di sfarfallio solo al personaggio danneggiato.
Logger.Print("Chiamata di StartOrResetFlickering per InAgent")
StartOrResetFlickering(InAgent)
FortCharacter.DamagedEvent().Await()
# Avvia un nuovo evento di sfarfallio se l'agente era invisibile, altrimenti
# ripristina l'effetto di sfarfallio attivo applicato all'agente.
StartOrResetFlickering(InAgent:agent):void=
if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]):
Logger.Print("Tentativo di attivare un NUOVO FlickerEvent per questo personaggio")
# Inizio di un nuovo effetto di sfarfallio.
if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds):
spawn{FlickerCharacter(FortCharacter)}
Logger.Print("FlickerEvent generato correttamente per questo personaggio")
else:
# Ripristina l'effetto di sfarfallio attivo.
if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds):
Logger.Print("Ripristina il FlickerTimer del personaggio a VulnerableSeconds")
# Restituisce se c'è altro tempo per mostrare l'effetto sfarfallio del giocatore
IsFlickering(InAgent:agent)<decides><transacts>:void=
PlayerVisibilitySeconds[InAgent] > 0.0
# Genera una funzione OnInfiltratorDamaged quando un nuovo infiltrato si unisce al gioco
OnInfiltratorJoined<public>(InAgent:agent):void=
spawn{OnInfiltratorDamaged(InAgent)}
# Gestisce un giocatore che si genera da una pedana di generazione degli infiltrati
OnPlayerSpawn(SpawnedAgent:agent):void=
Logger.Print("Si è appena generato un giocatore da una pedana di generazione degli infiltrati!")
if:
FortCharacter:fort_character = SpawnedAgent.GetFortCharacter[]
CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[SpawnedAgent]
AllTeams[0] = CurrentTeam
Logger.Print("Giocatore generato come infiltrato, rendendolo invisibile")
then:
FortCharacter.Hide()
item_capture_manager.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}
# Generatore di oggetti di cattura che genera gli oggetti da catturare.
@editable
CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{}
# Oggetto scenografico che fluttua sopra la testa di un giocatore quando è in possesso dell'oggetto.
# del CaptureItemSpawner.
@editable
CaptureItemIndicator:creative_prop = creative_prop{}
# Indicatore che mostra sulla mappa dove si trovano gli obiettivi di ogni team.
@editable
MapIndicator:map_indicator_device = map_indicator_device{}
# Frequenza di aggiornamento della posizione del CaptureItemIndicator.
@editable
UpdateRateSeconds:float = 0.15
# A che altezza sopra la testa del giocatore fluttua l'indicatore CaptureItemIndicator.
@editable
VerticalOffset:float = 180.0
# Visualizza un messaggio quando un giocatore afferra un oggetto conquistabile.
@editable
ItemGrabbedMessageDevice:hud_message_device = hud_message_device{}
# Quantità di tempo di attesa prima della restituzione del CaptureItem e degli indicatori della mappa.
# Un tempo negativo indica che gli indicatori non verranno mai restituiti a meno che l'obiettivo non venga
# riconquistato di nuovo.
@editable
ReturnTime:float = 10.0
# Assegna un punteggio a un giocatore quando cattura l'oggetto.
@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()
# Teletrasporta al generatore, nascondendo il CaptureItemIndicator dietro la mappa, in modo che non sia visibile.
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("Restituito beacon per generatore di creature")
# Segnala a tutti i giocatori quando un giocatore cattura l'obiettivo.
OnItemPickedUp(InAgent:agent):void=
Logger.Print("Obiettivo catturato")
if(FortCharacter := InAgent.GetFortCharacter[]):
ItemGrabbedMessageDevice.Show()
spawn{FollowCharacter(FortCharacter)}
# Quando un giocatore rilascia un oggetto, genera un funzione WaitForReturn()
# se il ReturnTime è maggiore di 0.
OnItemDropped(InAgent:agent):void=
Logger.Print("Obiettivo rilasciato")
if(ReturnTime >= 0.0):
spawn{WaitForReturn()}
else:
Logger.Print("L'obiettivo rilasciato non viene restituito")
# Quando l'oggetto viene catturato, assegna un punteggio al team che lo ha catturato e restituisce gli indicatori.
OnItemCaptured(CapturingAgent:agent):void=
Logger.Print("Obiettivo catturato")
ScoreManagerDevice.Activate()
ReturnIndicators()
# Attendi un periodo di tempo ReturnTime, quindi restituisci gli indicatori.
WaitForReturn()<suspends>:void=
Logger.Print("In attesa della restituzione degli indicatori...")
# Restituisce gli indicatori CaptureItem e Map se l'oggetto di cattura
# non è stato raccolto prima dello scadere del tempo.
ShouldReturn:logic := race:
block:
Sleep(ReturnTime)
vero
block:
CaptureItemSpawner.ItemPickedUpEvent.Await()
falso
if(ShouldReturn?):
ReturnIndicators()
# Fa sì che il CaptureItemIndicator sia mostrato sempre sopra la testa del giocatore.
# Viene eseguito durante il loop di aggiornamento per CaptureItemIndicator e verifica se il giocatore
# cattura l'oggetto, rilascia l'oggetto o viene eliminato.
FollowCharacter(FortCharacter:fort_character)<suspends>:void=
Logger.Print("Funzione FollowCharacter generata correttamente")
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)}
# Vogliamo assicurarci che questo loop venga eseguito una sola volta a ogni aggiornamento della simulazione, perciò inseriamo un evento di sospensione per il tick di gioco.
Sleep(0.0)
CaptureItemSpawner.ItemCapturedEvent.Await()
CaptureItemSpawner.ItemDroppedEvent.Await()
FortCharacter.EliminatedEvent().Await()
Logger.Print("Obiettivo rilasciato o catturato")
# Restituisce la mappa e gli indicatori di cattura di oggetti nelle loro posizioni iniziali sopra i generatori.
ReturnIndicators():void=
SpawnerTransform := CaptureItemSpawner.GetTransform()
# Teletrasporta al generatore, nascondendo il CaptureItemIndicator e il MapIndicator dietro la mappa in modo che non siano visibili.
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("Restituiti indicatori per generatore di creature")
In autonomia
Dopo aver completato questa guida, hai imparato a utilizzare Verse per creare un gioco in cui i team vengono bilanciati in modo simmetrico.
Utilizzando quello che hai imparato, prova a fare quanto segue:
- Prova a impostare diversi parametri per gli Infiltrati, gli Attaccanti e i Difensori al fine di creare la tua esperienza di gioco ideale. Cosa succederebbe se gli Infiltrati avessero armi da mischia? E se anche i Difensori fossero invisibili?
- Gli Infiltrati e gli Attaccanti possono combattere per lo stesso obiettivo? Vuoi provare a cambiare le condizioni di vittoria?