Completando questo passaggio nel tutorial Prova a tempo: A caccia di pizza, imparerai a gestire il punteggio quando un giocatore raccoglie e consegna gli oggetti e ad aggiornare l'interfaccia utente per visualizzare i punteggi. Per saperne di più sulla creazione di un'interfaccia utente di gioco in Verse, vedi Creare un'interfaccia utente in gioco.
Gestione punteggio terrà traccia e visualizzerà:
- Punti totali: rappresenta i punti totali che il giocatore ha totalizzato nel gioco.
- Punti in sospeso: rappresenta i punti accumulati dal giocatore per la serie attuale di oggetti raccoglibili.
- Livello di raccolta: rappresenta il livello di raccolta attuale.

Creazione dell'interfaccia utente
Per creare l'interfaccia utente di gestione punteggio in Verse, attieniti ai passaggi seguenti:
- Crea un nuovo file vuoto di Verse e nominalo score_manager.verse.
- Crea una nuova classe denominata
score_manager
, e aggiungi ad essa i campi seguenti:- Un
agent
opzionale denominatoMaybePlayer
per memorizzare un riferimento al giocatore.MaybePlayer<internal> : ?agent = false
- Un
player_ui
opzionale denominatoMaybePlayerUI
per memorizzare un riferimento all'interfaccia utente del giocatore.MaybePlayerUI<internal> : ?player_ui = false
- Un
score_manager_device
per memorizzare un riferimento al dispositivo Gestione punteggio in base a cui è costruita questa classe. (Nota: non si tratta di un riferimento modificabile, perché deve essere collegato al dispositivo creato da Versegame_coordinator_device
.ScoreManagerDevice<internal> : score_manager_device = score_manager_device{}
- Una variabile intera denominata
TotalGameScore
che rappresenta tutti i punti che il giocatore ha totalizzato nel corso della partita.var TotalGameScore<private> : int = 0
- Una variabile intera denominata
PendingScore
che rappresenta i punti che il giocatore ha attualmente segnato per questa serie di oggetti raccoglibili.var PendingScore<private> : int = 0
- Una variabile intera denominata
PickupLevel
che rappresenta il livello di raccolta attuale.var PickupLevel<private> : int = 0
- Un
- La definizione della tua classe score_manager dovrebbe ora essere simile a:
score_manager := class: MaybePlayer<internal> : ?agent = false MaybePlayerUI<internal> : ?player_ui = false ScoreManagerDevice<internal> : score_manager_device = score_manager_device{} var TotalGameScore<private> : int = 0 var PendingScore<private> : int = 0 var PickupLevel<private> : int = 0
- Crea l'interfaccia utente quando la classe viene creata per la prima volta. Puoi farlo aggiungendo un'espressione
block
alla definizione della classe, che verrà eseguita ogni volta che crei un'istanza della classe. Per generare l'interfaccia utente, aggiungi le seguenti variabili:- Una variabile
canvas
denominataCanvas
che contiene lo specificatoreinternal
per memorizzare la personalizzazione del widget canvas.var Canvas<internal> : canvas = canvas{}
- Un
text_block
denominatoTotalGameScoreWidget
che contiene lo specificatoreinternal
, per memorizzare il widget di testo per la visualizzazione di tutti i punti che il giocatore ha totalizzato nella partita, secondo quanto rappresentato dalla variabileTotalGameScore
. Imposta su bianco il colore predefinito del testo del blocco di testo.TotalGameScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White}
- Un
text_block
denominatoPendingScoreWidget
che contiene lo specificatoreinternal
, per memorizzare il widget di testo per la visualizzazione dei punti che il giocatore ha attualmente totalizzato per questa serie di oggetti raccoglibili, secondo quanto rappresentato dalla variabilePendingScore
. Imposta su bianco il colore predefinito del testo del blocco di testo.PendingScoreWidget<internal> : text_block = text_block{}
- Un
text_block
denominatoPickupLevelWidget
che contiene lo specificatoreinternal
, per memorizzare il widget di testo per la visualizzazione dei punti che il giocatore ha attualmente totalizzato per questo livello di oggetti raccoglibili, secondo quanto rappresentato dalla variabilePickupLevel
. Imposta su bianco il colore predefinito del testo del blocco di testo.PickupLevelWidget<internal> : text_block = text_block{}
- Una funzione che restituisce un
message
denominatoTotalGameScoreText
, che crea un testo localizzabile che può essere visualizzato nell'interfaccia utente per i punti totali che il giocatore ha totalizzato nel gioco.TotalGameScoreText<localizes>(CurrentTotalGameScore : int) : message = "Punti totali: {CurrentTotalGameScore}"
- Una funzione che restituisce un
message
denominatoPendingScoreText
che crea un testo localizzabile che può essere visualizzato nell'interfaccia utente per i punti che il giocatore ha attualmente totalizzato per questa serie di oggetti raccoglibili.PendingScoreText<localizes>(CurrentPendingScore : int) : message = "Punti in sospeso: {CurrentPendingScore}"
- Una funzione che restituisce un
message
denominatoPickupLevelText
che crea un testo localizzabile che può essere visualizzato nell'interfaccia utente per il livello di raccolta corrente.PickupLevelText<localizes>(CurrentPickupLevel : int) : message = "Livello di raccolta: {CurrentPickupLevel}"
- Aggiungi un'espressione
block
che crea il widget canvas e posiziona il testo impilato verticalmente sulla sinistra dello schermo.<# Poiché non ricreeremo canvas durante la durata di gestione punteggio, esegui questa operazione una volta, ogni volta che viene creato un oggetto di questo tipo. #> block: set Canvas = canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.25}, Maximum := vector2{X := 0.0, Y := 0.25} } Offsets := margin{Top := 0.0, Left := 25.0, Right := 0.0, Bottom := 0.0} Alignment := vector2{X := 0.0, Y := 0.0} SizeToContent := true Widget := stack_box: Orientation := orientation.Vertical Slots := array: stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := TotalGameScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PendingScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PickupLevelWidget
- Una variabile
- Il codice per
score_manager
dovrebbe ora essere simile a:using { /UnrealEngine.com/Temporary/UI } using { /Fortnite.com/UI } using { /Verse.org/Colors } score_manager := class: var Canvas<internal> : canvas = canvas{} TotalGameScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PendingScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PickupLevelWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} MaybePlayer<internal> : ?agent = false MaybePlayerUI<internal> : ?player_ui = false ScoreManagerDevice<internal> : score_manager_device = score_manager_device{} PickupLevelText<private><localizes>(InLevel : int) : message = "Livello di raccolta: {InLevel}" PendingScoreText<private><localizes>(InPoints : int) : message = "Punti in sospeso: {InPoints}" TotalGameScoreText<private><localizes>(InPoints : int) : message = "Punti totali: {InPoints}" var TotalGameScore<private> : int = 0 var PendingScore<private> : int = 0 var PickupLevel<private> : int = 0 <# Poiché non ricreeremo canvas durante la durata di gestione punteggio, esegui questa operazione una volta, ogni volta che viene creato un oggetto di questo tipo. #> block: set Canvas = canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.25}, Maximum := vector2{X := 0.0, Y := 0.25} } Offsets := margin{Top := 0.0, Left := 25.0, Right := 0.0, Bottom := 0.0} Alignment := vector2{X := 0.0, Y := 0.0} SizeToContent := true Widget := stack_box: Orientation := orientation.Vertical Slots := array: stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := TotalGameScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PendingScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PickupLevelWidget
- Crea una funzione denominata
UpdateUI()
che contiene lo specificatoreprivate
, che aggiorna il testo dell'interfaccia utente con gli ultimi valori di punteggio e il livello di raccolta attuale.UpdateUI<private>() : void = if (PlayerUI := MaybePlayerUI?): PickupLevelWidget.SetText(PickupLevelText(PickupLevel)) PendingScoreWidget.SetText(PendingScoreText(PendingScore)) PendingScoreWidget.SetText(TotalGameScoreText(TotalGameScore))
- Crea una funzione denominata
AddScoreManagerToUI()
che aggiorna l'interfaccia utente del giocatore con l'interfaccia utente personalizzata di gestione punteggio.AddScoreManagerToUI<public>() : void = if (PlayerUI := MaybePlayerUI?): PlayerUI.AddWidget(Canvas) UpdateUI()
- Crea una funzione per ogni valore visualizzato nell'interfaccia utente, in modo che il loop di gioco possa aggiornare i valori seguenti:
- Una funzione denominata
AddPendingScoreToTotalScore()
che contiene lo specificatorepublic
. Questa funzione deve aggiungere il punteggio in sospeso al punteggio totale della partita e reimpostare il valore del punteggio in sospeso a0
. Puoi eseguire ildefer
della reimpostazione diPendingScore
e dell'aggiornamento dell'interfaccia utente dopo che è stato completato l'aggiornamento diTotalGameScore
. In questo modo, si evita di utilizzare una variabile temporanea per mantenere il valore diPendingScore
prima che si reimposti.<# Aggiunge il PendingScore al TotalGameScore e reimposta il PendingScore a 0.#> AddPendingScoreToTotalScore<public>() : void = defer: set PendingScore = 0 UpdateUI() set TotalGameScore += PendingScore
- Una funzione denominata
UpdatePendingScore()
che contiene lo specificatorepublic
e un parametro intero chiamatoPoints
, che la funzione aggiungerà al punteggio in sospeso attuale.<# Aggiunge la quantità di punti indicata ai punti in sospeso. #> UpdatePendingScore<public>(Points : int) : void = set PendingScore += Points UpdateUI()
- Una funzione denominata
UpdatePickupLevel
che contiene lo specificatorepublic
e un parametro intero chiamatoLevel
, che corrisponde al nuovo valore per il livello di raccolta attuale.UpdatePickupLevel<public>(Level : int) : void = set PickupLevel = Level UpdateUI()
- Crea una funzione denominata
AwardScore()
contenente lo specificatorepublic
. Questa funzione assegna il punteggio al giocatore che utilizza il dispositivo Gestione punteggio e attiva tale dispositivo.<# Assegna il punteggio al giocatore con il dispositivo Gestione punteggio, eseguendone l'attivazione. #> AwardScore<public>() : void = ScoreManagerDevice.SetScoreAward(TotalGameScore) if (AwardedPlayer := MaybePlayer?): ScoreManagerDevice.Activate(AwardedPlayer)
- Una funzione denominata
- La classe
score_manager
dovrebbe ora essere simile a:score_manager := class: <# Poiché non ricreeremo canvas durante la durata di gestione punteggio, esegui questa operazione una volta, ogni volta che viene creato un oggetto di questo tipo. #> block: set Canvas = canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.25}, Maximum := vector2{X := 0.0, Y := 0.25} } Offsets := margin{Top := 0.0, Left := 25.0, Right := 0.0, Bottom := 0.0} Alignment := vector2{X := 0.0, Y := 0.0} SizeToContent := true Widget := stack_box: Orientation := orientation.Vertical Slots := array: stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := TotalGameScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PendingScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PickupLevelWidget AddScoreManagerToUI<public>() : void = if (PlayerUI := MaybePlayerUI?): PlayerUI.AddWidget(Canvas) UpdateUI() <# Aggiunge PendingPickupPoints a TotalPickupPoints e reimposta PendingPickupPoints a 0. Restituisce il numero totale di Punti di raccolta aggiunti. #> AddPendingScoreToTotalScore<public>() : void = set TotalGameScore += PendingScore defer: set PendingScore = 0 UpdateUI() <# Aggiunge la quantità di punti indicata ai punti in sospeso. #> UpdatePendingScore<public>(Points : int) : void = set PendingScore += Points UpdateUI() UpdatePickupLevel<public>(Level : int) : void= set PickupLevel = Level UpdateUI() <# Assegna il punteggio al giocatore con il dispositivo Gestione punteggio, eseguendone l'attivazione. #> AwardScore<public>() : void = ScoreManagerDevice.SetScoreAward(TotalGameScore) if (AwardedPlayer := MaybePlayer?): ScoreManagerDevice.Activate(AwardedPlayer) MaybePlayer<internal> : ?agent = false MaybePlayerUI<internal> : ?player_ui = false ScoreManagerDevice<internal> : score_manager_device = score_manager_device{} var Canvas<internal> : canvas = canvas{} TotalGameScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PendingScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PickupLevelWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PickupLevelText<private><localizes>(InLevel : int) : message = "Livello di raccolta: {InLevel}" PendingScoreText<private><localizes>(InPoints : int) : message = "Punti in sospeso: {InPoints}" TotalGameScoreText<private><localizes>(InPoints : int) : message = "Punti totali: {InPoints}" var TotalGameScore<private> : int = 0 var PendingScore<private> : int = 0 var PickupLevel<private> : int = 0 UpdateUI<private>() : void = if (PlayerUI := MaybePlayerUI?): PickupLevelWidget.SetText(PickupLevelText(PickupLevel)) PendingScoreWidget.SetText(PendingScoreText(PendingScore)) PendingScoreWidget.SetText(TotalGameScoreText(TotalGameScore))
- Ora che hai creato la classe
score_manager
, crea un costruttore per la classe per inizializzare le variabili del giocatore dal gioco. Devi eseguire il type cast del riferimento al giocatore daagent
aplayer
, per ottenere un riferimento all'interfaccia utente del giocatore.MakeScoreManager<constructor><public>(InPlayer : agent, InScoreManagerDevice : score_manager_device) := score_manager: MaybePlayer := option{InPlayer} MaybePlayerUI := option{GetPlayerUI[player[InPlayer]]}
- Il file score_manager.verse deve essere simile a:
using { /UnrealEngine.com/Temporary/SpatialMath } using { /UnrealEngine.com/Temporary/UI } using { /Fortnite.com/Devices } using { /Fortnite.com/UI } using { /Verse.org/Colors } using { /Verse.org/Simulation } MakeScoreManager<constructor><public>(InPlayer : agent, InScoreManagerDevice : score_manager_device) := score_manager: MaybePlayer := option{InPlayer} MaybePlayerUI := option{GetPlayerUI[player[InPlayer]]} score_manager := class: <# Poiché non ricreeremo canvas durante la durata di gestione punteggio, esegui questa operazione una volta, ogni volta che viene creato un oggetto di questo tipo. #> block: set Canvas = canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.25}, Maximum := vector2{X := 0.0, Y := 0.25} } Offsets := margin{Top := 0.0, Left := 25.0, Right := 0.0, Bottom := 0.0} Alignment := vector2{X := 0.0, Y := 0.0} SizeToContent := true Widget := stack_box: Orientation := orientation.Vertical Slots := array: stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := TotalGameScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PendingScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PickupLevelWidget AddScoreManagerToUI<public>() : void = if (PlayerUI := MaybePlayerUI?): PlayerUI.AddWidget(Canvas) UpdateUI() <# Aggiunge PendingPickupPoints a TotalPickupPoints e reimposta PendingPickupPoints a 0. Restituisce il numero totale di Punti di raccolta aggiunti. #> AddPendingScoreToTotalScore<public>() : int = set TotalGameScore += PendingScore defer: set PendingScore = 0 UpdateUI() return PendingScore <# Aggiunge la quantità di punti indicata ai punti in sospeso. #> UpdatePendingScore<public>(Points : int) : void = set PendingScore += Points UpdateUI() UpdatePickupLevel<public>(Level : int) : void= set PickupLevel = Level UpdateUI() <# Assegna il punteggio al giocatore con il dispositivo Gestione punteggio, eseguendone l'attivazione. #> AwardScore<public>() : void = ScoreManagerDevice.SetScoreAward(TotalGameScore) if (AwardedPlayer := MaybePlayer?): ScoreManagerDevice.Activate(AwardedPlayer) MaybePlayer<internal> : ?agent = false MaybePlayerUI<internal> : ?player_ui = false ScoreManagerDevice<internal> : score_manager_device = score_manager_device{} var Canvas<internal> : canvas = canvas{} TotalGameScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PendingScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PickupLevelWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PickupLevelText<localizes><internal>(CurrentPickupLevel : int) : message = "Livello di raccolta: {CurrentPickupLevel}" PendingScoreText<localizes><internal>(CurrentPendingScore : int) : message = "Punti in sospeso: {CurrentPendingScore}" TotalGameScoreText<localizes><internal>(CurrentTotalGameScore : int) : message = "Punti totali: {CurrentTotalGameScore}" var TotalGameScore<private> : int = 0 var PendingScore<private>:int = 0 var PickupLevel<private>:int = 0 UpdateUI<private>() : void = if (PlayerUI := MaybePlayerUI?): PickupLevelWidget.SetText(PickupLevelText(PickupLevel)) PendingScoreWidget.SetText(PendingScoreText(PendingScore)) PendingScoreWidget.SetText(TotalGameScoreText(TotalGameScore))
Aggiornamento del punteggio e dell'interfaccia utente nel loop di gioco
Per creare e aggiornare l'interfaccia utente durante la partita nel file game_coordinator_device.verse, attieniti ai passaggi seguenti:
- Aggiungi le seguenti proprietà alla classe
game_coordinator_device
:- Una variabile
score_manager
denominataScoreManager
contenente lo specificatoreprivate
. Questa istanza gestisce il punteggio e l'interfaccia utente del giocatore.var ScoreManager<private> : score_manager = score_manager{}
- Uno
score_manager_device
modificabile, che puoi impostare sul dispositivo Gestione punteggio del livello. È il dispositivo che utilizzerà la classescore_manager
.@editable ScoreManagerDevice<public> : score_manager_device = score_manager_device{}
- Un array di valori interi modificabile, denominato
PointsForPickupLevel
, che contiene lo specificatorepublic
, per definire i punti che il giocatore può totalizzare per ogni livello di raccolta.@editable # Esegue la mappatura di quanti punti vale un oggetto raccoglibile, in base al suo livello di raccolta. PointsForPickupLevel<public> : []int = array{1, 2, 3}
- Una variabile
-
Nella funzione
StartGame
, inizializza la variabile di Gestione punteggio chiamando il costruttoreMakeScoreManager()
con un riferimento al giocatore e al dispositivo Gestione punteggio, quindi genera l'interfaccia utente che verrà visualizzata dal giocatore.StartGame<private>()<suspends> : void = Logger.Print("Tentativo di avvio della partita...") <# Costruiamo un nuovo countdown_timer che, una volta avviato, eseguirà il conto alla rovescia a partire da InitialCountdownTime. Costruisci anche un nuovo score_manager che tenga traccia del punteggio del giocatore e del livello di raccolta. Gli elementi countdown_timer e score_manager richiedono un giocatore a cui mostrare le relative interfacce utente. A questo punto, dovremmo avere un giocatore valido: quello che è entrato nel veicolo, attivando l'avvio della partita. #> if (ValidPlayer := MaybePlayer?): Logger.Print("Giocatore valido, avvio della partita...") set ScoreManager = MakeScoreManager(ValidPlayer, ScoreManagerDevice) ScoreManager.AddScoreManagerToUI() set CountdownTimer = MakeCountdownTimer(InitialCountdownTime, ValidPlayer) CountdownTimer.StartCountdown() # Aspettiamo che il conto alla rovescia termini. # Allo stesso tempo, gestiamo anche il loop di gioco di raccolta e consegna che costituisce il nucleo del gameplay. race: HandleCountdownEnd(ValidPlayer) PickupDeliveryLoop() else: Logger.Print("Impossibile trovare un giocatore valido. Avvio della partita annullato", ?Level := log_level.Error)
- Nella funzione
PickupDeliveryLoop()
del loop di gioco, aggiorna l'interfaccia utente ogni volta che il livello di raccolta cambia e il giocatore termina una raccolta o una consegna:PickupDeliveryLoop<private>()<suspends> : void = PickupZonesTags : []pickup_zone_tag = array{pickup_zone_level_1_tag{}, pickup_zone_level_2_tag{}, pickup_zone_level_3_tag{}} MaxPickupLevel := PickupZonesTags.Length - 1 FirstPickupZoneCompletedEvent := event(){} loop: var PickupLevel : int = 0 var IsFirstPickup : logic = true <# Ogni volta che il loop si riavvia, dobbiamo reimpostare l'interfaccia utente del livello di raccolta attraverso ScoreManager. Nell'interfaccia utente, il livello di raccolta parte da 1 (non da 0). Alcuni giocatori si confonderanno, se inizia da 0. L'indice parte da 0, quindi PickupLevel=0 corrisponde al livello 1 nell'interfaccia utente. #> ScoreManager.UpdatePickupLevel(PickupLevel + 1) race: loop: if (PickupZone:base_zone = PickupZones[PickupLevel].SelectNext[]): PickupZone.ActivateZone() <# Questo è l'unico rinvio necessario per ogni PickupZone attivata. Disattiverà la prima PickupZone alla fine di ogni loop esterno, oppure disattiverà qualsiasi PickupZone successiva. Questo avviene perché l'espressione viene valutata alla fine, quando la variabile PickupZone è stata legata a una zona più recente. #> defer: PickupZone.DeactivateZone() PickupZone.ZoneCompletedEvent.Await() Logger.Print("Raccolto", ?Level:=log_level.Normal) # Dopo la prima raccolta, possiamo attivare la zona di consegna. if (IsFirstPickup?): set IsFirstPickup = false FirstPickupZoneCompletedEvent.Signal() if (PickupPoints := PointsForPickupLevel[PickupLevel]): ScoreManager.UpdatePendingScore(PickupPoints) # Aggiorna il livello di raccolta e ScoreManager. if (PickupLevel < MaxPickupLevel): set PickupLevel += 1 ScoreManager.UpdatePickupLevel(PickupLevel + 1) else: Logger.Print("PickupZone successiva da selezionare non trovata.", ?Level := log_level.Error) return # Errore in uscita dal PickupDeliveryLoop block: FirstPickupZoneCompletedEvent.Await() if (DeliveryZone := DeliveryZoneSelector.SelectNext[]): DeliveryZone.ActivateZone() # Rinviamo la disattivazione delle zone in modo che l'annullamento di PickupDeliveryLoop finisca per disattivare anche le zone di consegna attive. defer: Logger.Print("Disattivazione della zona di consegna.", ?Level := log_level.Normal) DeliveryZone.DeactivateZone() DeliveryZone.ZoneCompletedEvent.Await() Logger.Print("Consegnato", ?Level := log_level.Normal) ScoreManager.AddPendingScoreToTotalScore() else: Logger.Print("DeliveryZone successiva da selezionare non trovata.", ?Level := log_level.Error) return # Errore in uscita dal PickupDeliveryLoop
- A questo punto, al termine del conto alla rovescia, assegna al giocatore il suo punteggio. In
HandleCountdownEnd()
, chiamaScoreManager.AwardScore()
.HandleCountdownEnd<private>(InPlayer : player)<suspends>:void= TotalTime := CountdownTimer.CountdownEndedEvent.Await() ScoreManager.AwardScore() EndGame.Activate(InPlayer)
- Il tuo file game_coordinator_device.verse deve essere simile a:
using { /Verse.org/Simulation } using { /Fortnite.com/Devices } using { /Fortnite.com/Vehicles } using { /Fortnite.com/Characters } using { /Fortnite.com/Playspaces } using { /Verse.org/Random } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath } using { /EpicGames.com/Temporary/Curves } using { /Verse.org/Simulation/Tags } # Tag delle zone di gioco pickup_zone_tag<public> := class(tag): pickup_zone_level_1_tag<public> := class(pickup_zone_tag): pickup_zone_level_2_tag<public> := class(pickup_zone_tag): pickup_zone_level_3_tag<public> := class(pickup_zone_tag): delivery_zone_tag<public> := class(tag): log_pizza_pursuit<internal> := class(log_channel){} game_coordinator_device<public> := class(creative_device): # Per quanto tempo il timer del conto alla rovescia inizierà il conto alla rovescia. @editable InitialCountdownTime<public> : float = 30.0 @editable EndGame<public> : end_game_device = end_game_device{} @editable ScoreManagerDevice<public> : score_manager_device = score_manager_device{} @editable # Esegue la mappatura di quanti punti vale un oggetto raccoglibile, in base al suo livello di raccolta. PointsForPickupLevel<public> : []int = array{1, 2, 3} OnBegin<override>()<suspends> : void = FindPlayer() SetupZones() StartGame() Logger<private> : log = log{Channel := log_pizza_pursuit} var MaybePlayer<private> : ?agent = false var CountdownTimer<private> : countdown_timer = countdown_timer{} var ScoreManager<private> : score_manager = score_manager{} DeliveryZoneSelector<private> : tagged_zone_selector = tagged_zone_selector{} var PickupZoneSelectors<private> : []tagged_zone_selector = array{} FindPlayer<private>() : void = # Poiché si tratta di un'esperienza per giocatore singolo, il primo giocatore (0) # deve essere l'unico disponibile. Playspace := Self.GetPlayspace() if (FirstPlayer := Playspace.GetPlayers()[0]): set MaybePlayer = option{FirstPlayer} Logger.Print("Giocatore trovato") else: # Registra un errore se non riusciamo a trovare un giocatore. # Questo non deve accadere perché almeno un giocatore è sempre presente. Logger.Print("Impossibile trovare un giocatore valido", ?Level := log_level.Error) SetupZones<private>() : void = # Esiste un solo tipo di zona di consegna, in quanto non è ridimensionabile in base al livello di difficoltà. DeliveryZoneSelector.InitZones(delivery_zone_tag{}) # Utilizziamo i tag di gameplay per selezionare le zone (rappresentate dai dispositivi), in base al loro livello di difficoltà. # L'utilizzo di un array rende più semplice la modifica dei livelli di difficoltà: possiamo aggiungere altri # livelli, aumentare/diminuire la loro granularità o cambiarne l'ordine senza toccare il codice. # Crea un tagged_zone_selector per ogni tag di livello di difficoltà, in modo che tutti i dispositivi con lo stesso tag (cioè lo stesso livello di difficoltà) # finiscano nel medesimo pool di selezione. LevelTags : []pickup_zone_tag = array{pickup_zone_level_1_tag{}, pickup_zone_level_2_tag{}, pickup_zone_level_3_tag{}} set PickupZoneSelectors = for (ZoneTag : LevelTags): NewZone := tagged_zone_selector{} NewZone.InitZones(ZoneTag) NewZone StartGame<private>()<suspends> : void = Logger.Print("Tentativo di avvio della partita...") <# Costruiamo un nuovo countdown_timer che, una volta avviato, eseguirà il conto alla rovescia a partire da InitialCountdownTime. Costruisci anche un nuovo score_manager che tenga traccia del punteggio del giocatore e del livello di raccolta. Gli elementi countdown_timer e score_manager richiedono un giocatore a cui mostrare le relative interfacce utente. A questo punto, dovremmo avere un giocatore valido: quello che è entrato nel veicolo, attivando l'avvio della partita. #> if (ValidPlayer := MaybePlayer?): Logger.Print("Giocatore valido, avvio della partita...") set ScoreManager = MakeScoreManager(ValidPlayer, ScoreManagerDevice) ScoreManager.AddScoreManagerToUI() set CountdownTimer = MakeCountdownTimer(InitialCountdownTime, ValidPlayer) CountdownTimer.StartCountdown() # Aspettiamo che il conto alla rovescia termini. # Allo stesso tempo, gestiamo anche il loop di gioco di raccolta e consegna che costituisce il nucleo del gameplay. race: HandleCountdownEnd(ValidPlayer) PickupDeliveryLoop() else: Logger.Print("Impossibile trovare un giocatore valido. Avvio della partita annullato", ?Level := log_level.Error) HandleCountdownEnd<private>(InPlayer : agent)<suspends> : void = CountdownTimer.CountdownEndedEvent.Await() ScoreManager.AwardScore() EndGame.Activate(InPlayer) PickupDeliveryLoop<private>()<suspends> : void = PickupZonesTags : []pickup_zone_tag = array{pickup_zone_level_1_tag{}, pickup_zone_level_2_tag{}, pickup_zone_level_3_tag{}} MaxPickupLevel := PickupZonesTags.Length - 1 FirstPickupZoneCompletedEvent := event(){} loop: var PickupLevel : int = 0 var IsFirstPickup : logic = true <# Ogni volta che il loop si riavvia, dobbiamo reimpostare l'interfaccia utente del livello di raccolta attraverso ScoreManager. Nell'interfaccia utente, il livello di raccolta parte da 1 (non da 0). Alcuni giocatori si confonderanno, se inizia da 0. L'indice parte da 0, quindi PickupLevel=0 corrisponde al livello 1 nell'interfaccia utente. #> ScoreManager.UpdatePickupLevel(PickupLevel + 1) race: loop: if (PickupZone:base_zone = PickupZoneSelectors[PickupLevel].SelectNext[]): PickupZone.ActivateZone() <# Questo è l'unico rinvio necessario per ogni PickupZone attivata. Disattiverà la prima PickupZone alla fine di ogni loop esterno, oppure disattiverà qualsiasi PickupZone successiva. Questo avviene perché l'espressione viene valutata alla fine, quando la variabile PickupZone è stata legata a una zona più recente. #> defer: PickupZone.DeactivateZone() PickupZone.ZoneCompletedEvent.Await() Logger.Print("Raccolto", ?Level := log_level.Normal) # Dopo la prima raccolta, possiamo attivare la zona di consegna. if (IsFirstPickup?): set IsFirstPickup = false FirstPickupZoneCompletedEvent.Signal() if (PickupPoints := PointsForPickupLevel[PickupLevel]): ScoreManager.UpdatePendingScore(PickupPoints) # Aggiorna il livello di raccolta e ScoreManager. if (PickupLevel < MaxPickupLevel): set PickupLevel += 1 ScoreManager.UpdatePickupLevel(PickupLevel + 1) else: Logger.Print("PickupZone successiva da selezionare non trovata.", ?Level := log_level.Error) return # Errore in uscita dal PickupDeliveryLoop block: FirstPickupZoneCompletedEvent.Await() if (DeliveryZone := DeliveryZoneSelector.SelectNext[]): DeliveryZone.ActivateZone() # Rinviamo la disattivazione delle zone in modo che l'annullamento di PickupDeliveryLoop finisca per disattivare anche le zone di consegna attive. defer: Logger.Print("Disattivazione della zona di consegna.", ?Level := log_level.Normal) DeliveryZone.DeactivateZone() DeliveryZone.ZoneCompletedEvent.Await() Logger.Print("Consegnato", ?Level := log_level.Normal) ScoreManager.AddPendingScoreToTotalScore() else: Logger.Print("DeliveryZone successiva da selezionare non trovata.", ?Level := log_level.Error) return # Errore in uscita dal PickupDeliveryLoop