Puoi creare i tuoi componenti utilizzando Verse per aggiungerli alle tue entità. Con i componenti Verse personalizzati, puoi generare e rimuovere entità dalla scena, aggiungere o rimuovere componenti dalle entità, creare i tuoi propri comportamenti come un'entità che scompare in un loop o qualsiasi cosa ti venga in mente!
Creazione di un nuovo componente Verse
È possibile creare un nuovo componente Verse dal file modello Verse.
Per creare un nuovo componente Verse:
Nel pannello Dettagli dell'entità, scegli Aggiungi componente > Nuovo componente Verse.
Puoi anche creare un nuovo componente Verse aggiungendo un nuovo file Verse tramite Verse Explorer.
Dall'elenco dei modelli di codice Verse, scegli Componente Scene Graph.
Imposta Nome componente sul nome del componente creato con Verse. In questo esempio, il componente è denominato
my_verse_component.Fai clic su Crea per creare il file del componente Verse. Il componente Verse ora viene visualizzato nell'elenco dei componenti quando scegli di aggiungere un componente all'entità.
Puoi aggiungere solo una delle classi o sottoclassi del componente indicato. Ad esempio, puoi avere un solo mesh_component su un'entità. Questo si estende alle sottoclassi dei componenti, il che significa che se aggiungi un capsule_light_component alla tua entità, non puoi aggiungere anche un rect_light_component poiché entrambe sono sottoclassi di light_component. La stessa limitazione si applica ai componenti personalizzati realizzati in Verse.
Durata del componente
I componenti si spostano attraverso una serie di funzioni di durata man mano che vengono aggiunti alle entità, aggiunti alla scena e iniziano a essere eseguiti nella simulazione. I componenti creati da Verse devono eseguire l'override di questi metodi per l'impostazione e l'esecuzione della simulazione.
Quando un componente viene arrestato, si sposta nella versione di arresto di queste funzioni, offrendo l'opportunità di ripulire qualsiasi stato mantenuto sul componente prima che venga eliminato.
Di seguito sono riportati gli stati di durata di un componente:
Inizializzato
AddedToScene
BeginSimulation
EndSimulation
RemovingFromScene
Annullamento inizializzazione in corso
Le funzioni di durata di un componente sono diverse dalle durate del dispositivo. La logica dei componenti viene eseguita sia in modalità di modifica che di riproduzione. Qualsiasi comportamento aggiunto verrà eseguito immediatamente all'avvio della sessione. Se vuoi che la logica del componente venga eseguita solo all'avvio del gioco, puoi generare prefab nella funzione OnBegin() di un dispositivo Verse.
Interrogare entità e componenti con Verse
Esistono diversi modi per trovare entità e componenti nel codice Verse. Il modo in cui strutturi le entità e i componenti influisce sul modo in cui esegui query e sviluppi funzionalità nel codice Verse.
L'esecuzione di query su entità e componenti in Verse richiede di iniziare con un'entità e di restituire entità nidificate sopra o sotto di essa nella gerarchia. Puoi eseguire una query per il genitore diretto o i figli diretti di un'entità e anche per tutte le entità antenate e discendenti.
Determinare entità con il tipo di componente
Puoi trovare tutte le entità che dispongono di un componente di un tipo specifico chiamando l'entità su cui eseguire una query. Se l'entità su cui esegui la query è l'entità di simulazione, nella scena restituisce tutte le entità con componenti di quel tipo.
Nell'esempio seguente, il componente Verse determina tutte le entità a cui è collegato il componente light_component. Per ciascuna delle entità che trova, genera un particle_sytem_component e lo collega a esse. In questo caso, BlowingParticles è un emettitore Niagara a cui si fa riferimento nel file Assets.digest.Verse.
Il light_component è una superclasse per tutti i diversi tipi di componenti luce che puoi aggiungere alle tue entità. Nella query seguente, LightComponent viene utilizzato per trovare le entità con qualsiasi tipo di componente luce su di esse.
# Runs when the component should start simulating in a running game.
OnBeginSimulation<override>():void =
# Run OnBeginSimulation from the parent class before
# running this component's OnBeginSimulation logic
(super:)OnBeginSimulation()
for:
LightComponent : Entity.GetSimulationEntity[].FindDescendantEntitiesWithComponent(light_component)
do:
# Create a particle system component and add it to the entity.
L'esempio successivo mostra come eseguire una query per tutte le entità che hanno sistemi particellari nidificati sotto l'entità a cui è collegato il componente Verse utilizzando la funzione FindDescendantEntitiesWithComponent(). Allo stesso modo, puoi anche determinare tutte le entità antenate con un particolare componente utilizzando FindAncestorEntitiesWithComponent().
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Get all entities that have particle system components nested under the entity this component is attached to.
ParticleSystemEntities := Entity.FindDescendantEntitiesWithComponent(particle_system_component)
# Get all entities with particle system components that are ancestors of this entity.
Se è necessario eseguire query sulle entità dell'intera scena, puoi farlo ottenendo l'entità di simulazione ed eseguendo le query su di essa. Questa operazione inizia nella parte superiore della struttura dell'entità e trova tutte le entità nidificate che corrispondono alla query. Per accedere all'entità di simulazione, chiama la funzione fallibile GetSimulationEntity[] sull'entità a cui è collegato il componente Verse.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Get the simulation entity.
if:
SimulationEntity := Entity.GetSimulationEntity[]
then:
Fare in modo che il componente Verse guardi costantemente su e giù l'albero delle entità può essere costoso. Se il comportamento dipende da una struttura di entità specifica, qualsiasi modifica minima alla struttura dell'entità può causare modifiche involontarie al comportamento o il mancato funzionamento.
D'altra parte, questo significa anche che il tuo componente può richiedere meno configurazione perché tutto ciò che devi fare è aggiungere il tuo componente Verse e avere la struttura dell'entità corretta. Tieni a mente questi compromessi mentre crei le tue entità e sviluppi la logica del tuo componente Verse.
Esplora il modulo SceneGraph per scoprire tutti i modi in cui utilizzare entità e componenti in Verse. Di seguito vengono descritti alcuni modi comuni per interrogare entità e componenti nel codice.
Determinare i componenti di un'entità
Puoi utilizzare Verse per determinare un componente di un tipo specifico su un'entità chiamando GetComponent[]. Ciò è utile per creare una logica personalizzata che dipende dal comportamento di altri componenti. Ad esempio, utilizzando il sound_component per riprodurre l'audio in base al colore di una luce o determinando un particle_system_component per applicare effetti a seconda che l'entità si trovi all'interno di una determinata zona.
Nell'esempio seguente, il componente Verse fa apparire e scomparire ripetutamente una piattaforma in un loop. A tale scopo, determina il componente mesh sull'entità e lo disabilita, quindi lo riabilita dopo una durata impostata.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SceneGraph }
# A Verse-authored component that can be added to entities.
# This component will make the entity appear and disappear on loop.
disappear_on_loop_component := class<final_super>(component):
# How long in seconds the entity should be hidden.
@editable
In un altro esempio, il componente Verse determina il light_component sull'entità e ne cambia il colore in arancione scuro. light_component è una superclasse di tutti i tipi di luci che puoi aggiungere alle tue entità, quindi questo esempio trova tutti i componenti che ne derivano.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Find any component on this entity that subclasses from light_component.
if:
LightComponent := Entity.GetComponent[light_component]
then:
Determinare tutti i componenti
Puoi utilizzare la funzione GetComponents() per restituire tutti i componenti dell'entità. Poiché il codice non sa di che tipo si tratta, puoi utilizzare il casting per eseguire operazioni diverse in base al tipo di ogni componente. L'esempio seguente determina un array di tutti i componenti di un'entità e tenta di eseguirne il casting nel tipo enableable. Se il casting riesce, il componente implementa l'interfaccia enableable. Quindi disabilita ogni componente che implementa questa interfaccia.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Get a list of all components on the entity.
ComponentList := Entity.GetComponents()
for:
Component:ComponentList
Trovare entità tramite tag di gameplay
Puoi aggiungere un componente tag alle entità per poter trovare entità specifiche all'interno della scena, similmente alla possibilità di aggiungere Tag di gameplay agli attori. Ciò è utile per scegliere le entità da utilizzare invece di fare affidamento su elementi modificabili, ad esempio i componenti che hanno o dove si trovano nella scena.
Questo perché fare affidamento su elementi modificabili può causare comportamenti indesiderati nel gioco quando si modificano e si aggiungono nuove entità al progetto. Puoi aggiungere tag nell'editor aggiungendo un tag_component all'entità e selezionando i tag dal menu a discesa Tags oppure nel codice Verse utilizzando la funzione AddTag().
L'esempio seguente interroga l'entità di simulazione per tutti i discendenti contrassegnati con il tag my_tag sul loro tag_component.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically cancelled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void =
# Get the simulation entity.
if:
SimulationEntity := Entity.GetSimulationEntity[]
then:
Trovare entità con le sovrapposizioni
I volumi di collisione sono volumi che rappresentano le forme di collisione delle mesh. Puoi utilizzarli per interrogare oggetti sovrapposti all'interno di una determinata forma, ad esempio danneggiare gli oggetti se si avvicinano troppo a una torre o rilevare quando un pallone da calcio entra in una porta. In Verse, puoi utilizzare la funzione FindOverlapHits() per trovare tutte le entità all'interno di una particolare area.
Questa area può essere l'entità stessa, un dato volume di collisione come una sfera o una scatola o una posizione da cui simulare l'entità. Restituisce quindi un elenco di overlap_hit. Ogni overlap_hit fornisce informazioni sul componente o sul volume sovrapposto al volume di origine e puoi interrogare questi componenti per trovare l'entità associata.
L'esempio seguente crea una sfera con un raggio di 256.0 unità centrata sulla trasformazione dell'entità. Quindi trova tutte le sovrapposizioni all'interno della sfera, restituendo un elenco di overlap_hit. Dato che ogni overlap_hit è un componente o un volume, puoi interrogare TargetComponent o TargetVolume per sapere di quale tipo si tratta. Se overlap_hit è un componente, il codice determina l'entità del componente. Infine, controlla se l'entità ha un componente luce. In caso affermativo, trasforma il colore della luce in blu. Con un volume abbastanza grande, puoi cambiare il colore di ogni luce sulla tua isola con poche righe di codice!
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Define a volume to find entities within.
# This is a sphere whose radius is 256.
CollisionSphere:collision_sphere = collision_sphere:
Radius := 256.0
Questo codice simula un volume collision_sphere sovrapposto indicato dal cerchio con raggio di 256,0 unità centrato sull'entità cubo, restituendo eventuali componenti o volumi con cui la sfera si sovrappone. Quindi ottiene l'entità genitore di ogni componente sovrapposto e fa diventare blu tutti i componenti di luce su di essa. Poiché il cubo si trova all'interno della collision_sphere quando inizia la sovrapposizione, viene incluso nell'elenco di overlap_hits e diventa anche blu. Tieni presente che l'entità cono rosso più a destra si trova al di fuori della collision_sphere, quindi non si sovrappone e non diventa blu.
Trovare le entità con i sweep
Un altro modo importante per eseguire query sulle entità è attraverso gli sweep. Lo sweeping si riferisce allo spostamento di un oggetto per una determinata distanza lungo un determinato vettore. Ad esempio, puoi spostare un blocco su una piattaforma per spingere i giocatori in un varco o lanciare un missile in avanti per distruggere un muro.
In Verse, puoi simulare gli sweep per interrogare le collisioni tra oggetti utilizzando la funzione FindSweepHits(). Questa funzione utilizza un vettore di spostamento per simulare lo sweeping di un oggetto. Puoi eseguire sweep con l'entità genitore o un determinato volume di collisione e specificare la trasformazione globale iniziale da cui iniziare lo sweeping.
La funzione FindSweepHits() restituisce un elenco di sweep_hit. Ogni sweep_hit fornisce le stesse informazioni di un overlap_hit, come ad esempio il riscontro di componente o di volume, nonché il volume o il componente di origine che esegue lo sweep. Fornisce inoltre informazioni sulla posizione di contatto, sulla normale, normale della faccia e sulla distanza lungo lo sweep dove si è verificato il riscontro.
L'esempio seguente prende un'entità e chiama FindSweepHit(), passando un vettore con una lunghezza di 1000.0 per il valore Forward. Il codice simula quindi quali collisioni si verificherebbero se l'entità fosse spostata di 1000,0 unità nella direzione in avanti positiva e restituisce un elenco di sweep_hit.
Dato che ogni sweep_hit è un componente o un volume, puoi interrogare TargetComponent o TargetVolume per sapere di quale tipo si tratta. Se l'hit è un componente, il codice ottiene l'entità genitore del componente. Infine, controlla se l'entità ha un componente luce. In caso affermativo, trasforma il colore della luce in blu.
for:
# Simulate sweeping this entity 1000 units in the positive X direction, and return any components and volumes it overlaps with.
SweepHit : Entity.FindSweepHits(vector3{Left := 0.0, Up := 0.0, Forward := 1000.0}, Entity.GetGlobalTransform(), CollisionBox)
# Check that the overlap is a component, and if so get its parent entity.
# Then if the entity has a light component, change its color filter.
TargetComponent := SweepHit.TargetComponent
TargetEntity := TargetComponent.Entity
LightComponent := TargetEntity.GetComponent[light_component]
do:
Questo codice simula lo sweeping dell'entità cubo di 1000,0 unità nella direzione X positiva, restituendo eventuali componenti con cui si sovrappone. Quindi ottiene l'entità genitore del componente sovrapposto e fa diventare blu tutti i componenti di luce su di essa. Tieni presente che l'elenco dei risultati non include l'entità che esegue lo sweep, quindi il cubo stesso non diventa blu. Anche l'entità cono rosso più a destra non diventa blu poiché si trova al di fuori dello sweep.
Questo esempio successivo è simile al precedente, tranne per il fatto che prima costruisce un volume collision_box e poi lo utilizza per eseguire lo sweep di 1000.0 unità nella direzione in avanti positiva, a partire dal centro dell'entità cubo. Dato che il cubo si trova all'interno della collision_box quando inizia lo sweep, viene incluso nell'elenco di sweep_hits e diventa anche blu.
# Define a volume to sweep over entities.
# This box is 1/4th the size of a standard 512x512 grid tile.
CollisionBox:collision_box = collision_box:
Extents := vector3:
Left := 128.0,
Up := 128.0,
Forward := 128.0
for:
# Simulate sweeping the CollisionBox 1000 units in the positive X direction, and return any components and volumes it overlaps with.
SweepHit : Entity.FindSweepHits(vector3{Left := 0.0, Up := 0.0, Forward := 1000.0}, Entity.GetGlobalTransform(), CollisionBox)
Questo codice simula lo sweeping di un volume collision_box indicato dal quadrato giallo di 1000,0 unità nella direzione in avanti positiva, restituendo tutti i componenti con cui si sovrappone. Quindi ottiene l'entità genitore del componente sovrapposto e fa diventare blu tutti i componenti di luce su di essa. Poiché il cubo si trova all'interno della collision_box quando inizia lo sweep, viene incluso nell'elenco di sweep_hits e diventa blu. L'entità cono rosso più a destra non diventa blu perché si trova al di fuori dello sweep.
Generazione e rimozione di entità con Verse
Puoi rimuovere un'entità dalla scena chiamando RemoveFromParent() sull'entità. Puoi aggiungere un'entità alla scena, nuova o rimossa in precedenza, chiamando AddEntities() sull'entità che diventa l'entità genitore.
Nell'esempio seguente, il componente Verse trova tutte le entità contrassegnate con il tag di gameplay my_tag. Rimuove ogni entità trovata dal suo genitore, che rimuove l'entità dalla scena, e aggiunge di nuovo la stessa entità al suo genitore dopo cinque secondi per generarla di nuovo nella scena.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically cancelled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void =
# Find all entities tagged and get their parent entity.
for:
TaggedEntity : Entity.GetSimulationEntity[].FindDescendantEntitiesWithTag(my_tag{})
Parent := TaggedEntity.GetParent[]
Allo stesso modo, puoi aggiungere componenti a un'entità chiamando AddComponents() e passando l'elenco dei componenti che vuoi aggiungere. Puoi anche rimuovere un'entità chiamando RemoveFromParent() sull'entità e puoi rimuovere un componente da un'entità chiamando RemoveFromEntity() sul componente. Le entità e i componenti rimossi si possono aggiungere di nuovo alla scena rispettivamente con AddEntities() e AddComponents(). Tieni presente che non puoi modificare l'entità genitore dei componenti rimossi e aggiunti di nuovo alla scena.
Prefabbricati
I prefab creati nel progetto vengono esposti come classe a Verse nel file Assets.digest.verse del tuo progetto. Le entità e i componenti definiti nel prefab sono accessibili in Verse attraverso le chiamate GetEntities() e GetComponents() su un prefab.
Puoi generare istanze dei prefabbricati creando un'istanza della classe del prefabbricato e aggiungendole a un'entità nella scena. Nell'esempio seguente, il componente Verse crea un'istanza del prefab, denominata loop_disappearing_platform_prefab nell'editor, e la aggiunge alla scena.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically cancelled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void =
if:
SimulationEntity := Entity.GetSimulationEntity[]
then:
# Create an instance of the disappearing on loop platform from its prefab.
DisappearingPlatform:disappearing_platform_prefab = disappearing_platform_prefab{}
Buone prassi e suggerimenti
Quando crei i tuoi componenti in Verse, tieni a mente le seguenti buona prassi e suggerimenti:
I componenti Verse che si basano su altri componenti dovrebbero generalmente trovarsi sulla stessa entità.
I componenti espongono eventi tick sia pre-fisica sia post-fisica, che si verificano a ogni frame. Ciò è utile se è necessario eseguire una determinata logica prima dell'applicazione della fisica, ad esempio modificando la trasformazione e, dopo, ad esempio, per leggere le posizioni degli oggetti dopo la fisica.
Se non sono necessari gli eventi pre-fisici o post-fisici in modo specifico, è necessario continuare a utilizzare le espressioni di concorrenza Verse per controllare il flusso temporale in base a una determinata logica. Per ulteriori dettagli, vedi Flusso temporale e concorrenza.
Le funzioni di durata di un componente sono diverse dalle durate del dispositivo. La logica dei componenti viene eseguita sia in modalità di modifica che di riproduzione. Se vuoi che la logica del componente venga eseguita solo all'avvio del gioco, puoi generare prefab nella funzione
OnBegin()di un dispositivo Verse.