I medici sono un archetipo di personaggio comune in molti giochi. Il compito di un medico è quello di curare i personaggi vicini e di aiutare i compagni di squadra a riprendersi dopo aver subito un danno. I medici svolgono ruoli diversi a seconda del gioco, ad esempio i medici che servono i pazienti in un ospedale, i medici da combattimento che aiutano il loro team a combattere e a curare, o le stazioni neutre che curano chiunque.
Il personaggio medico che creerai in questo esempio segue una serie di regole logiche.
- Inattivo:
- Avvia agenti di guarigione
- Loop di guarigione
- Passa ad agente
Il medico inizia inattivo e pattuglia fino a quando un agente non entra nella zona di guarigione. Quell'agente viene aggiunto alla coda di guarigione del medico. Il medico deve tenere traccia dell'agente che deve curare successivamente e una coda fornisce una struttura dati utile a questo scopo, poiché le code sono una struttura dati first-in, first-out. Ciò significa che il personaggio che entra per primo nella zona di guarigione sarà il primo a essere guarito.
Una volta ottenuto l'agente da curare, il medico controlla innanzitutto se la salute dell'agente è inferiore alla soglia di guarigione. In caso affermativo, inizia a curarli a una velocità specifica fino a quando la salute dell'agente non raggiunge la soglia o l'agente non esce dalla zona di guarigione. Durante la guarigione, il medico cercherà di rimanere vicino all'agente dirigendosi continuamente verso di lui. Una volta che la salute dell'agente è tornata alla soglia, il medico prende l'agente successivo da curare e ricomincia il processo. Se non ci sono agenti da curare, il medico torna a essere inattivo.
Puoi visualizzare la logica del PNG medico utilizzando la macchina a stati finiti sottostante. Per maggiori informazioni sulle macchine a stati finiti, consulta Comprendere il comportamento dei PNG.

Completando questa guida, imparerai a creare un personaggio medico personalizzato utilizzando lo Script comportamento PNG che guarisce gli altri personaggi vicini quando la loro salute è inferiore a una certa soglia. Lo script completo è incluso come riferimento alla fine di questa guida.
Creazione di un nuovo script del comportamento PNG
Per iniziare a creare il tuo personaggio PNG medico, crea un nuovo script comportamento PNG chiamato medic_example. Per maggiori informazioni sulla creazione del tuo script comportamento PNG, consulta la sezione Crea il tuo comportamento PNG personalizzato. Apri il file Verse in Visual Studio Code.
Segui questi passaggi per creare uno script di comportamento PNG in UEFN che generi un personaggio medico che cura i giocatori vicini.
Implementazione della coda di guarigione
Lo script comportamento PNG inizia con vari valori utilizzati per il movimento del personaggio e la visualizzazione di debug. Non ti serviranno tutti in questo script, quindi rimuovi ora il codice non necessario.
-
All'inizio della definizione della classe
medic_example
, rimuovi i valori prima diOnBegin()
. Il tuo medico non aspetterà di spostarsi verso i personaggi, ma li seguirà durante la guarigione. Non hai bisogno dei valori di debug per questo esempio e utilizzerai altri oggetti per visualizzare quando il tuo medico guarisce i personaggi. -
In
OnBegin()
, dopo aver ottenuto le interfacce del personaggio nella prima istruzioneif
, rimuovi il codice all'interno dell'istruzionethen
. Il tuo personaggio medico non ha bisogno di eseguire il loop tra i punti dopo essersi generato, ma pattuglierà intorno al suo punto di generazione in attesa di personaggi da curare. -
Rimuovi le funzioni
DrawDebugLocation()
eDrawDebugLookAt()
. In questo esempio non utilizzerai i valori di debug, quindi non ti servono nemmeno le funzioni associate che li utilizzano.
Dopo aver rimosso il codice non necessario, puoi iniziare a costruire il tuo personaggio medico.
-
All'inizio della definizione della classe
medic_example
, aggiungi i seguenti valori:-
float modificabile
HealingThreshold
. Questa è la soglia di salute che i personaggi devono avere per ricevere la guarigione.# La soglia di PS che un personaggio deve raggiungere prima di essere guarito. @editable HealingThreshold:float = 50.0
-
Aggiungi un float modificabile
HealingDelay
. È la quantità di tempo di attesa tra un'istanza di guarigione e l'altra, durante la guarigione dei personaggi. A seconda che tu voglia che il medico guarisca più lentamente o più velocemente, cambia il valore di conseguenza.# La soglia di PS che un personaggio deve raggiungere prima di essere guarito. @editable HealingThreshold:float = 50.0 # Tempo di attesa prima della guarigione dei personaggi @editable HealingDelay:float = 1.5
-
Float modificabile
HealingAmount
. Questa è la quantità di salute da curare dei personaggi per istanza di guarigione. Quando il PNG medico guarisce un personaggio, lo guarisce di unaHealingAmount
ogniHealingDelay
secondi.# Tempo di attesa prima della guarigione dei personaggi @editable HealingDelay:float = 1.5 # Determina la quantità di guarigione da applicare ai personaggi per istanza di guarigione @editable HealingAmount:float = 5.0
-
Zona mutatore modificabile
HealVolume
. Questo è il volume in cui i personaggi entrano per ricevere la guarigione. In questo esempio utilizzerai una zona mutatore perché essa presenta unAgentEntersEvent
a cui il tuo medico può iscriversi e controllare i personaggi che potrebbero aver bisogno di essere curati.# Determina la quantità di guarigione da applicare ai personaggi per istanza di guarigione @editable HealingAmount:float = 5.0 # Volume in cui entrano i personaggi per ricevere la guarigione. @editable HealVolume:mutator_zone_device = mutator_zone_device{}
-
Generatore VFX modificabile
VFXSpawner
. Il feedback visivo è importante per sapere che il tuo codice funziona, quindi userai un generatore VFX per generare gli effetti, quando un personaggio viene guarito.# Volume in cui entrano i personaggi per ricevere la guarigione. @editable HealVolume:mutator_zone_device = mutator_zone_device{} # Generatore VFX per riprodurre VFX mentre i personaggi vengono guariti. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {}
-
Variabile opzionale
agent
denominataAgentToFollow
. Memorizza un riferimento al personaggio che il medico deve seguire mentre lo cura.# Generatore VFX per riprodurre VFX mentre i personaggi vengono guariti. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {} # Agente da seguire mentre vengono guariti var AgentToFollow:?agent = false
-
Coda variabile di agenti denominata
AgentsToHeal
. Se più personaggi hanno bisogno di essere curati, il tuo medico curerà i personaggi in base all'ordine in cui sono entrati nelHealVolume
. Il codice della coda verrà impostato nel passaggio successivo. Per maggiori informazioni sulla struttura dei dati della coda, consulta stack e code in verse.# Agente da seguire mentre vengono guariti var AgentToFollow:?agent = false # Coda di agenti da guarire nel caso in cui più agenti entrino nel volume di guarigione. var AgentsToHeal<public>:queue(agent) = queue(agent){}
-
Float variabile
UpdateRateSeconds
. È la quantità di tempo di attesa tra l'aggiornamento della posizione delHealVolume
e delVFXSpawner
.# Coda di agenti da guarire nel caso in cui più agenti entrino nel volume di guarigione. var AgentsToHeal<public>:queue(agent) = queue(agent){} # Utilizzato per specificare la velocità di aggiornamento della posizione di HealVolume e di VFXSpawner UpdateRateSeconds<private>:float = 0.1
-
-
Per implementare la coda
AgentsToHeal
, utilizzerai il codice fornito alla fine di questo passaggio.- Torna in Verse Explorer, fai clic con il tasto destro del mouse sul nome del tuo progetto e scegli Aggiungi nuovo file Verse al progetto per aprire la finestra Crea script Verse.
-
Nella finestra Crea script Verse, fai clic su Classe di Verse per selezionarla come script.
-
Assegna un nome alla tua classe Verse cambiando il testo del campo Nome classe in
queue
. -
Fai clic su Crea per creare il file Verse.
-
In Verse Explorer fai due volte clic sul nome del file Verse per aprirlo in Visual Studio Code.
-
Sostituisci il codice nel tuo file
queue
con il seguente codice. Questo codice implementa una coda generica di tipotype
utilizzando una struttura dati elenco. Questo è un esempio di tipo parametrico, poiché l'implementazione della coda funzionerà indipendentemente dal tipo da cui viene creata. Nel tuo esempio, utilizzerai una coda di personaggi, quindi la definizione della coda inmedic_example
saràqueue(agent)
.list(t:type) := class: Data:t Next:?list(t) queue<public>(t:type) := class<internal>: Elements<internal>:?list(t) = false Size<public>:int = 0 Enqueue<public>(NewElement:t):queue(t) = queue(t): Elements := option: list(t): Data := NewElement Next := Elements Size := Size + 1 Dequeue<public>()<decides><transacts>:tuple(queue(t), t) = List := Elements? (queue(t){Elements := List.Next, Size := Size - 1}, List.Data) Front<public>()<decides><transacts>:t = Elements?.Data CreateQueue<public><constructor>(InData:t where t:type) := queue(t): Elements := option: list(t): Data := InData Next := false Size := 1
-
Organizzare i tuoi script Verse in cartelle distinte può essere d'aiuto per l'organizzazione, oltre a fornire un modo per fare facilmente riferimento ai file più utilizzati. A titolo di esempio, in questo progetto creerai una cartella per memorizzare i comportamenti dei PNG. In Visual Studio Code, premi il pulsante Nuova cartella per creare una nuova cartella nel tuo progetto UEFN. Denomina la cartella
npc_behaviors
. Quindi trascina il tuo file Versemedic_example
nella nuova cartella.
Il tuo codice in medic_example
ora deve essere compilato correttamente.
Guarigione dei personaggi all'interno del volume
Quando un personaggio ferito entra nel HealVolume
, il tuo medico deve iniziare a guarirlo se la sua salute è inferiore alla HealingThreshold
. Quando la salute del personaggio supera la HealingThreshold
, il medico deve smettere di guarire quel personaggio e passare al personaggio successivo che ha bisogno di essere curato. Nel caso di più personaggi, il medico deve guarire i personaggi nell'ordine in cui sono entrati nel HealVolume
. Segui questi passaggi per guarire i personaggi quando entrano nel HealVolume
.
-
Nel file
medic_example
, inOnBegin()
dopo l'istruzionethen
, inizia unloop
. All'interno delloop
, ottieni il risultato della funzioneDequeue()
dalla codaAgentsToHeal
e salvalo in una variabileDequeueResult
.then: loop: # Ottieni il prossimo agente in coda da guarire. Se c'è un agente da curare, guariscilo chiamando AgentToHeal. # Se non ci sono agenti da guarire, aspetta che un agente entri in HealVolume if: DequeueResult := AgentsToHeal.Dequeue[]
-
La variabile
DequeueResult
è unatuple
che restituisce una copia della codaAgentsToHeal
con il primo elemento rimosso e l'agente in testa alla coda. AggiornaAgentsToHeal
impostandolo sul primo valore della tupla e salva il secondo valore comeAgentToHeal
.if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1)
-
Una volta che hai l'agente da guarire, devi iniziare a curarlo mentre si trova nel
HealVolume
. Definirai una nuova funzione chiamataHealCharacter()
per gestire questo aspetto. Aggiungi una nuova funzione denominataHealCharacter()
alla definizione della classemedic_example
. Questa funzione prende come argomenti della funzione le interfacce diAgentToHeal
, siaNavigatable
cheFocusable
dei personaggi medici. Aggiungi il modificatore<suspends>
a questa funzione, poiché deve eseguire diversi task asincroni quando guarisce un personaggio.# Guarisci il personaggio, poi attendi un tempo di HealingDelayAmount. # Termina quando la salute del personaggio raggiunge HealingThreshold # o il personaggio abbandona il HealVolume. HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void=
-
In
HealCharacter
, controlla se l'AgentToHeal
si trova nel volume chiamandoIsInVolume[]
e passandoAgentToHeal
come argomento. Se l'agente si trova nel volume, puoi iniziare a guarirlo. Tutti gli agenti guaribili implementano l'interfacciahealthful
che fa parte delfort_character
dell'agente. Ottieni ilfort_character
dell'agente e salvalo in un valoreCharacterToHeal
.HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void= # Guarisci il personaggio solo se si trova all'interno di HealVolume if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[]
-
Quando il personaggio è pronto a essere guarito, devi assicurarti che il tuo medico rimanga vicino al personaggio da curare. Crea un
navigation_target
daAgentToHeal
utilizzandoMakeNavigationTarget
e salvalo in una variabileNavigationTarget
. Poi, in un'istruzionebranch
, chiama la funzioneNavigateTo()
utilizzando l'interfaccianavigatable
del PNG, per far sì che il tuo medico si sposti verso l'AgentToHeal
. Sempre nella funzionebranch
, chiama la funzioneMaintainFocus()
per assicurarti che il tuo medico si concentri sull'AgentToHeal
. L'uso di un'istruzionebranch
in questo contesto ti permette di eseguire siaNavigateTo()
cheMaintainFocus()
in modo asincrono allo stesso tempo e di eseguire immediatamente qualsiasi codice dopo ilbranch
. Per maggiori informazioni sulle espressioni branch, consulta la pagina branch in Verse.# Guarisci il personaggio solo se si trova all'interno di HealVolume if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] then: Print("Il personaggio è nel volume e sta iniziando a guarire") NavigationTarget := MakeNavigationTarget(AgentToHeal) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal)
-
Abilita il
VFXSpawner
per riprodurre i VFX mentre il tuo medico guarisce un personaggio. Quindi, in un'espressionedefer
, disabilita ilVFXSpawner
. Poiché il codice per disabilitare ilVFXSpawner
è contenuto in un'espressionedefer
, non verrà eseguito fino all'uscita dall'ambito attuale. In questo caso, significa che il codice verrà eseguito solo quando la funzione termina, quindi è garantito che rappresenti l'ultima cosa che accade nella funzione. Per maggiori informazioni sulle espressioni defer, consulta la pagina defer.branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable()
-
Durante la cura del
CharacterToHeal
, la guarigione deve interrompersi quando si verifica una delle due condizioni. O la salute del personaggio viene curata oltre laHealingThreshold
, oppure il personaggio esce dalHealVolume
. Per ottenere questo risultato, utilizzerai un'espressionerace
. Imposta un'espressionerace
tra unloop
e unAwait()
sull'HealVolume.AgentExitsEvent.
branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() race: loop: HealVolume.AgentExitsEvent.Await()
-
All'interno del
loop
, ottieni la salute attuale del personaggio utilizzandoGetHealth()
e salvala in un valoreCurrentHealth
. Quindi, in un'istruzioneif
, controlla se laCurrentHealth
più laHealingAmount
è maggiore dellaHealingThreshold
. In caso affermativo, il tuo medico deve interrompere la guarigione ed eseguire ilbreak
del loop. Tuttavia, se la salute attuale del personaggio è di poco inferiore alla soglia di guarigione, vuoi che sia curato fino alla soglia di guarigione. Aggiungi una seconda istruzioneif
all'interno della prima, che controlla seCurrentHealth
è inferiore allaHealingThreshold
. In caso affermativo, imposta la salute del personaggio allaHealingThreshold
.race: loop: CurrentHealth := CharacterToHeal.GetHealth() if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("Il personaggio ha raggiunto la soglia di guarigione, arresto guarigione in corso") break HealVolume.AgentExitsEvent.Await()
-
Altrimenti, se la
CurrentHealth
più laHealingAmount
non è maggiore dellaHealingThreshold
, imposta la salute del personaggio allaCurrent Health
, più laHealingAmount
.if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("Il personaggio ha raggiunto la soglia di guarigione, arresto guarigione in corso") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount)
-
Alla termine del
loop
, sospendi per una quantità di tempo pari aHealingDelay
. Senza questa sospensione, i personaggi saranno guariti a ogni aggiornamento della simulazione, quindi ilHealingDelay
impedirà loro di essere curati istantaneamente. Il codice completatoHealCharacter()
deve essere simile al seguente.# Guarisci il personaggio, poi attendi un tempo di HealingDelayAmount. # Termina quando la salute del personaggio raggiunge HealingThreshold # o il personaggio abbandona il HealVolume. HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void= # Guarisci il personaggio solo se si trova all'interno di HealVolume if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] then: Print("Il personaggio è nel volume e sta iniziando a guarire") NavigationTarget := MakeNavigationTarget(AgentToHeal) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() race: loop: CurrentHealth := CharacterToHeal.GetHealth() if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("Il personaggio ha raggiunto la soglia di guarigione, arresto guarigione in corso") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount) Sleep(HealingDelay) HealVolume.AgentExitsEvent.Await()
-
Torna a
OnBegin()
, nell'espressionethen
all'interno del tuoloop
, chiamaHealCharacter()
passando l'AgentToHeal
, l'interfacciaNavigable
e l'interfacciaFocusable
.if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: Print("È stato rimosso dalla coda il prossimo agente da guarire") HealCharacter(AgentToHeal, Navigatable, Focusable)
-
Il tuo medico non avrà sempre un personaggio da guarire vicino a sé e la funzione
Dequeue[]
avrà un esito negativo, se non ci sono agenti nella codaAgentsToHeal
. Per gestire questo problema, aggiungi un'istruzioneelse
al termine delloop
. All'interno di questa istruzioneif
, chiamaSleep()
per una quantità di tempoHealingDelay
, quindiAwait()
per l'eventoHealVolume.AgentEntersEvent
. In questo modo, il personaggio medico non chiamerà all'infinitoDequeue[]
sulla coda degliAgentsToHeal
, ma aspetterà che un nuovo personaggio entri nelHealVolume
, prima di riavviare il loop. Il loop completato deve essere simile al seguente.loop: # Ottieni il prossimo agente in coda da guarire. Se c'è un agente da curare, guariscilo chiamando AgentToHeal. # Se non ci sono agenti da guarire, aspetta che un agente entri in HealVolume if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: Print("È stato rimosso dalla coda il prossimo agente da guarire") HealCharacter(AgentToHeal, Navigatable, Focusable) else: Print("AgentsToHeal è vuoto!") Sleep(HealingDelay) HealVolume.AgentEntersEvent.Await()
Tracciare quando i personaggi si trovano nel volume di guarigione
Per sapere quando i personaggi entrano o escono dal HealVolume
, dovrai iscriverti a entrambe le funzioni AgentEntersEvent
e AgentExitsEvent
del HealVolume
.
-
Aggiungi una nuova funzione denominata
OnAgentEnters()
alla definizione della classemedic_example
. Questa funzione prende gli agenti che sono appena entrati nelHealVolume
e li inserisce nella codaAgentsToHeal
.OnAgentEnters(EnteredAgent:agent):void= Print("L'agente è entrato nel volume di guarigione")
-
In
OnAgentEnters()
, controlla che l'agente nel volume non sia il personaggio medico. In caso affermativo, imposta la codaAgentsToHeal
sul risultato della chiamata diEnqueue[]
con l'EnteredAgent
. La funzione completataOnAgentEnters()
deve essere simile alla seguente:OnAgentEnters(EnteredAgent:agent):void= Print("L'agente è entrato nel volume di guarigione") if (EnteredAgent <> GetAgent[]): set AgentsToHeal = AgentsToHeal.Enqueue(EnteredAgent)
-
Quando un agente esce dall'
HealVolume
, non è necessario rimuoverlo dalla codaAgentsToHeal
. Ciò avviene perché il loop presente inOnBegin()
chiama giàDequeue[]
in un loop. Tuttavia, nei tuoi esempi potresti eseguire del codice quando un agente esce dal volume, quindi ora dovrai impostare una funzione per questo. Aggiungi una nuova funzione denominataOnAgentExits()
alla definizione della classemedic_example
.OnAgentExits(ExitAgent:agent):void= Print("L'agente è uscito dal volume di guarigione")
-
In
OnBegin()
, iscriviAgentEntersEvent
eAgentExitsEvent
dell'HealVolume
aOnAgentEnters
eOnAgentExits
, rispettivamente. Dal momento che dovrebbe iniziare disabilitato, questo è un buon momento per chiamareDisable()
sul generatore di personaggi.OnBegin<override>()<suspends>:void= Print("Ciao, IA!") VFXSpawner.Disable() HealVolume.AgentEntersEvent.Subscribe(OnAgentEnters) HealVolume.AgentExitsEvent.Subscribe(OnAgentExits)
Spostamento del volume di guarigione con il medico
Quando il personaggio medico si muove, HealVolume
deve spostarsi con lui per adattarsi alla sua posizione attuale. Lo stesso vale per VFXSpawner
. Per eseguire questa operazione, utilizzerai una nuova funzione DeviceFollowCharacter()
.
-
Aggiungi una nuova funzione denominata
DeviceFollowCharacter()
alla definizione della classemedic_example
. Questa funzione deve essere eseguita in modo asincrono per aggiornare continuamente le posizioni dei dispositivi, quindi aggiungi il modificatore<suspends>
.DeviceFollowCharacter()<suspends>:void=
-
All'interno della funzione
DeviceFollowCharacter()
, ottieni ilfort_character
del medico ottenendo prima l'agente utilizzandoGetAgent[]
e poi chiamandoGetFortCharater[]
.DeviceFollowCharacter()<suspends>:void= if: # Ottieni l'agente (personaggio AI) a cui è associato questo comportamento. Agent := GetAgent[] # Ottieni l'interfaccia fort_character dell'agente per accedere ai comportamenti, agli eventi, alle funzioni e alle interfacce specifiche del personaggio di Fortnite. Character := Agent.GetFortCharacter[]
-
Ora devi spostare continuamente il
HealVolume
e ilVFXSpawner
nella posizione delCharacter
. Per farlo, eseguirai un loopMoveTo()
su entrambi i dispositivi. Avvia unloop
e ottieni la trasformazione delCharacter
e salvala in una variabileCharacterTransform
.if: # Ottieni l'agente (personaggio AI) a cui è associato questo comportamento. Agent := GetAgent[] # Ottieni l'interfaccia fort_character dell'agente per accedere ai comportamenti, agli eventi, alle funzioni e alle interfacce specifiche del personaggio di Fortnite. Character := Agent.GetFortCharacter[] then: loop: CharacterTransform := Character.GetTransform()
-
Chiama
MoveTo()
sia perVFXSpawner
che perHealVolume
, spostandoli inCharacterTransform.Translation
eCharacterTransform.Rotation
. Imposta la durata suUpdateRateSeconds
secondi. Infine, chiamaSleep()
per una quantità di tempoUpdateRateSeconds
, per evitare che i dispositivi aggiornino la loro posizione a ogni aggiornamento della simulazione. L'aggiornamento della posizione del dispositivo a ogni aggiornamento della simulazione può causare un movimento irregolare dei dispositivi. Il codice completatoDeviceFollowCharacter()
deve essere simile al seguente.DeviceFollowCharacter()<suspends>:void= if: # Ottieni l'agente (personaggio AI) a cui è associato questo comportamento. Agent := GetAgent[] # Ottieni l'interfaccia fort_character dell'agente per accedere ai comportamenti, agli eventi, alle funzioni e alle interfacce specifiche del personaggio di Fortnite. Character := Agent.GetFortCharacter[] then: loop: CharacterTransform := Character.GetTransform() VFXSpawner.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds) HealVolume.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds) Sleep(UpdateRateSeconds)
-
In
OnBegin()
, dopo l'istruzioneif
in cui salvi le interfacce dei personaggi ma prima del loop, genera un'istanza diDeviceFollowCharacter()
.
Aggiunta del tuo personaggio al livello
-
Crea una nuova definizione del personaggio PNG chiamata Medico. Fai clic sulla definizione del tuo nuovo PNG per aprire la schermata Definizione personaggio PNG.
-
Nella schermata Definizione personaggio PNG, modifica le seguenti proprietà:
-
In Tipo personaggio PNG, imposta Tipo su Guardia. L'interfaccia della guardia ti permette di accedere alle funzionalità specifiche del personaggio, come gli eventi per quando la guardia è allertata o sospettosa e ti permette di assoldare guardie da utilizzare come alleati. Le guardie possono anche equipaggiare armi, mentre i personaggi di tipo Personalizzato e Animali selvatici attualmente non possono. Puoi anche cambiare il nome del tuo personaggio nella scheda Nome.
-
In Comportamento personaggio PNG, imposta Comportamento su Comportamento Verse. Quindi imposta lo Script comportamento NPG su
medic_example
. Il tuo personaggio avrà ancora accesso alle funzionalità dell'interfaccia di guardia, ma utilizzerà il tuo script Verse per decidere come procedere duranteOnBegin
eOnEnd
. -
Nella scheda Modificatori, sotto Modificatore di generazione guardia, fai clic sulla scheda Estetica per modificare l'aspetto estetico del tuo personaggio. Puoi scegliere un'estetica preesistente o attivare il Retargeting estetica personaggio per utilizzare un modello personalizzato. Tieni presente che solo le guardie e i personaggi di tipo personalizzato possono utilizzare il retargeting estetica del personaggio, mentre gli animali selvatici non possono farlo. Per maggiori informazioni sui modificatori dei personaggi e su quali si applicano ai diversi tipi di personaggi, consulta la pagina Definizione personaggio.
-
-
Salva la definizione del tuo personaggio PNG. In Esplora contenuti, trascina la definizione del tuo personaggio PNG nel livello. Ciò creerà automaticamente un nuovo generatore personaggio e gli assegnerà la definizione del tuo personaggio PNG.

-
Trascina una zona mutatore e un dispositivo generatore VFX nel livello.
-
Seleziona il tuo generatore personaggio. In Outliner, sotto Opzioni utente:
-
Imposta Override script AIBehavior sul tuo script
medic_example
. Eseguire l'override dello scriptAIBehavior
nell'outliner ti permette di fare riferimento ai dispositivi del livello e questa funzionalità ti servirà per assegnare i tuoi HealVolume e VFXSpawner. -
Imposta HealVolume sulla zona del mutatore e VFXSpawner sul generatore VFX che hai posizionato nel livello.
-

-
Seleziona la tua zona mutatore. In Outliner, sotto Opzioni utente, imposta Zona visibile in gioco su Vero. Ciò ti aiuterà a visualizzare dove si trova il
HealVolume
e come si sposta insieme al personaggio medico. -
Seleziona il tuo generatore VFX. In Outliner, sotto Opzioni utente, imposta Effetto visivo su un effetto di tua scelta. Questo esempio utilizza l'effetto Bolle per trasmettere la guarigione, ma potresti utilizzare qualcosa di diverso, come fuochi d'artificio o scintille. Cambia l'effetto visivo per adattarlo alle esigenze del tuo personaggio.
-
Fai clic su Avvia sessione nella barra degli strumenti UEFN per eseguire il playtest del tuo livello. Quando esegui il playtest, il tuo personaggio deve guarire i personaggi feriti che entrano nella zona mutatore. Durante la guarigione di un personaggio, i VFX devono essere riprodotti e il medico deve seguire e concentrarsi sul personaggio da curare.

Script completo
Il seguente è uno script completo per un personaggio PNG che cura i personaggi i cui PS sono al di sotto di una certa soglia.
medic_example.verse
using { /Fortnite.com/AI }
using { /Fortnite.com/Characters }
using { /Fortnite.com/Devices }
using { /Verse.org/Colors }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
# Comportamento PNG creato da Verse che si può utilizzare all'interno di una definizione PNG o di un override dello script di comportamento di un dispositivo Generatore di personaggi.
medic_example<public> := class(npc_behavior):
# La soglia di PS che un personaggio deve raggiungere prima di essere guarito.
@editable
HealingThreshold:float = 50.0
# Tempo di attesa prima della guarigione dei personaggi
@editable
HealingDelay:float = 1.5
# Determina la quantità di guarigione da applicare ai personaggi per istanza di guarigione
@editable
HealingAmount:float = 5.0
# Volume in cui entrano i personaggi per ricevere la guarigione.
@editable
HealVolume:mutator_zone_device = mutator_zone_device{}
# Generatore VFX per riprodurre VFX mentre i personaggi vengono guariti.
@editable
VFXSpawner:vfx_spawner_device = vfx_spawner_device {}
# Agente da seguire mentre vengono guariti
var AgentToFollow:?agent = false
# Coda di agenti da guarire nel caso in cui più agenti entrino nel volume di guarigione.
var AgentsToHeal<public>:queue(agent) = queue(agent){}
# Utilizzato per specificare la velocità di aggiornamento della posizione di HealVolume e di VFXSpawner
UpdateRateSeconds<private>:float = 0.1
OnBegin<override>()<suspends>:void=
VFXSpawner.Disable()
HealVolume.AgentEntersEvent.Subscribe(OnAgentEnters)
HealVolume.AgentExitsEvent.Subscribe(OnAgentExits)
if:
# Ottieni l'agente (personaggio AI) a cui è associato questo comportamento.
Agent := GetAgent[]
# Ottieni l'interfaccia fort_character dell'agente per accedere ai comportamenti, agli eventi, alle funzioni e alle interfacce specifiche del personaggio di Fortnite.
Character := Agent.GetFortCharacter[]
# Ottieni l'interfaccia navigabile del personaggio per impostare destinazioni specifiche verso i quali il personaggio può viaggiare.
Navigatable := Character.GetNavigatable[]
# Ottieni la focus_interface del personaggio per impostare destinazioni specifiche su cui possono concentrarsi dopo averle raggiunte.
Focusable := Character.GetFocusInterface[]
then:
# Imposta HealVolume e VFXSpawner in modo che seguano continuamente il personaggio PNG
spawn{DeviceFollowCharacter()}
loop:
# Ottieni il prossimo agente in coda da guarire. Se c'è un agente da curare, guariscilo chiamando AgentToHeal.
# Se non ci sono agenti da guarire, aspetta che un agente entri in HealVolume
if:
DequeueResult := AgentsToHeal.Dequeue[]
set AgentsToHeal = DequeueResult(0)
AgentToHeal := DequeueResult(1)
then:
PrintNPCB("È stato rimosso dalla coda il prossimo agente da guarire")
HealCharacter(AgentToHeal, Navigatable, Focusable)
else:
PrintNPCB("AgentsToHeal è vuoto!")
Sleep(HealingDelay)
HealVolume.AgentEntersEvent.Await()
else:
# Se il codice qui ha esito negativo, qualcosa non è andato a buon fine durante la raccolta dell'agente e delle relative interfacce
PrintNPCB( "Errore nello script del comportamento del PNG durante l'impostazione del PNG",
?Duration := 6.0,
?TextColor := NamedColors.Red )
# Guarisci il personaggio, poi attendi un tempo di HealingDelayAmount.
# Termina quando la salute del personaggio raggiunge HealingThreshold
# o il personaggio abbandona il HealVolume.
HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)<suspends>:void=
# Guarisci il personaggio solo se si trova all'interno di HealVolume
if:
HealVolume.IsInVolume[AgentToHeal]
CharacterToHeal := AgentToHeal.GetFortCharacter[]
then:
PrintNPCB("Il personaggio è nel volume e sta iniziando a guarire")
NavigationTarget := MakeNavigationTarget(AgentToHeal)
branch:
Navigatable.NavigateTo(NavigationTarget)
Focusable.MaintainFocus(AgentToHeal)
VFXSpawner.Enable()
defer:
VFXSpawner.Disable()
race:
loop:
CurrentHealth := CharacterToHeal.GetHealth()
if(CurrentHealth + HealingAmount > HealingThreshold):
if (CurrentHealth < HealingThreshold):
CharacterToHeal.SetHealth(HealingThreshold)
PrintNPCB("Il personaggio ha raggiunto la soglia di guarigione, arresto guarigione in corso")
break
else:
CharacterToHeal.SetHealth(CurrentHealth + HealingAmount)
Sleep(HealingDelay)
HealVolume.AgentExitsEvent.Await()
# Imposta HealVolume e VFXSpawner in modo che seguano continuamente il personaggio con un loop
# MoveTo sulla posizione del personaggio.
DeviceFollowCharacter()<suspends>:void=
if:
# Ottieni l'agente (personaggio AI) a cui è associato questo comportamento.
Agent := GetAgent[]
# Ottieni l'interfaccia fort_character dell'agente per accedere ai comportamenti, agli eventi, alle funzioni e alle interfacce specifiche del personaggio di Fortnite.
Character := Agent.GetFortCharacter[]
then:
# Esegui un loop MoveTo su HealVolume e VFXSpawner per far corrispondere la loro posizione a quella del
# personaggio PNG
loop:
CharacterTransform := Character.GetTransform()
VFXSpawner.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds)
HealVolume.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds)
Sleep(UpdateRateSeconds)
# Quando un agente entra nel HealVolume, aggiungilo alla coda
# AgentsToHeal se non è il personaggio PNG.
OnAgentEnters(EnteredAgent:agent):void=
PrintNPCB("L'agente è entrato nel volume di guarigione")
if (EnteredAgent <> GetAgent[]):
set AgentsToHeal = AgentsToHeal.Enqueue(EnteredAgent)
# Quando un agente esce da HealVolume, PrintNPCB nel registro
OnAgentExits(ExitAgent:agent):void=
PrintNPCB("L'agente è uscito dal volume di guarigione")
# Wrapper personalizzato che fornisce una durata e un colore predefiniti.
PrintNPCB(Msg:string,?Duration:float = 3.0, ?TextColor:color = NamedColors.Green):void =
Print("[new_npc_behavior] {Msg}", ?Color := TextColor, ?Duration := Duration)
# Questa funzione viene eseguita quando il PNG viene rimosso o eliminato dal mondo.
OnEnd<override>():void =
if(Agent := GetAgent[]):
Print(medic_example_message_module.OnEndMessage(Agent))
else:
PrintNPCB("OnEnd")
queue.verse
list(t:type) := class:
Data:t
Next:?list(t)
queue<public>(t:type) := class<internal>:
Elements<internal>:?list(t) = false
Size<public>:int = 0
Enqueue<public>(NewElement:t):queue(t) =
queue(t):
Elements := option:
list(t):
Data := NewElement
Next := Elements
Size := Size + 1
Dequeue<public>()<decides><transacts>:tuple(queue(t), t) =
List := Elements?
(queue(t){Elements := List.Next, Size := Size - 1}, List.Data)
Front<public>()<decides><transacts>:t = Elements?.Data
CreateQueue<public><constructor>(InData:t where t:type) := queue(t):
Elements := option:
list(t):
Data := InData
Next := false
Size := 1
In autonomia
Dopo aver completato questa guida, hai imparato a creare un personaggio medico che guarisce automaticamente i personaggi al di sotto di una certa soglia. Utilizzando ciò che hai imparato, prova a creare il tuo personaggio medico con i suoi comportamenti speciali.
-
Puoi creare un medico che passa da un volume di danno a uno di guarigione in base alla presenza di un nemico nel volume?
-
Che ne dici di un medico che utilizza una risorsa esauribile per guarire i personaggi? In che modo il medico potrebbe ripristinare questa risorsa? Può ripristinarla nel tempo o può farlo attaccando i nemici?