Le lanterne nel tutorial Scene Graph utilizzano più componenti creati da Verse creare prefab dinamici e interattivi. Ciò è possibile con la programmazione del movimento e dell'interattività in un componente creato da Verse.
Simulazione di movimento semplice
Il prefab lampione utilizza due componenti diversi per simulare il movimento della lanterna. Entrambi sono collegati all'entità pivot, che fornisce un punto cardine per spostare la lanterna. Innanzitutto, keyframed_movement_component ti permette di costruire animazioni dai keyframe e poi riprodurli per animare un'entità. Questo componente, tuttavia, non può agire da solo e ha bisogno di un altro pezzo di codice per fornire i keyframe e avviare l'animazione. È qui che entra in gioco il componente personalizzato simple_movement_component. Questo script viene riutilizzato nel progetto per controllare come si muovono i diversi oggetti di gioco nella scena.
Per saperne di più sull'utilizzo delle animazioni per spostare gli oggetti, dai un'occhiata a Animazione del movimento dell'oggetto scenografico.
Diamo un'occhiata più da vicino a simple_movement_component. Per iniziare, apri lo script SimpleMovementComponent.verse da Verse Explorer in Visual Studio Code.
Le animazioni utilizzano diverse modalità di riproduzione per definire cosa deve fare l'animazione quando viene completata. Ciò è definito all'inizio del file nell'enum motion_mode:
One Shot - L'oggetto smette di muoversi quando termina l'animazione.
Loop - L'oggetto riavvia l'animazione dall'inizio quando raggiunge la fine.
Ping Pong - L'oggetto riproduce l'animazione al contrario, andando avanti e indietro dall'inizio alla fine.
movement_mode<public> := enum:
OneShot
Loop
PingPongLa classe basic_movement_component definisce anche le variabili necessarie per costruire le animazioni. Ognuna ha l'attributo @editable che ti permette di modificarle dall'outliner:
Keyframes: array dikeyframed_movement_deltautilizzato per costruire l'animazione. Ognuno tiene traccia della modifica nella trasformazione di questo particolare keyframe, della durata del keyframe e del tipo di andamento del movimento utilizzato.AutoPlay: variabilelogicache determina se l'entità deve animarsi quando inizia la simulazione.MovementMode: comportamento di movimento visualizzato dall'entità.
# A Verse-authored component that can be added to entities
basic_movement_component<public> := class<final_super>(component):
@editable
var Keyframes<public>: []keyframed_movement_delta = array{}
@editable
var AutoPlay: logic = true
Il codice in OnSimulate() inizia a essere eseguito ogni volta che il componente viene aggiunto alla scena e quando inizia il gioco. In questo caso, il codice utilizza una breve chiamata Sleep() per assicurarsi che tutte le entità e i componenti siano inizializzati correttamente prima di procedere. Quindi, in un'espressione if, controlla se l'entità ha un keyframed_movement_component.
In caso affermativo, chiama la funzione InitializeKeyFramedMovementComponent() per impostare il componente con i valori corretti. Cosa succede se l'entità non ha un keyframed_movement_component? In tal caso, puoi crearne uno dinamicamente in runtime e aggiungerlo all'entità utilizzando la funzione AddComponents(). In questo modo garantisci che la tua entità sia impostata correttamente all'inizio del gioco!
OnSimulate<override>()<suspends>:void =
Sleep (0.1)
if:
KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
InitializeKeyframedMovementComponent(KeyframedMovementComponent)
else:
NewKeyFramedMovementComponent := keyframed_movement_component { Entity := Entity }
Entity.AddComponents of array { NewKeyFramedMovementComponent }
InitializeKeyframedMovementComponent(NewKeyFramedMovementComponent)La funzione InitializeKeyframedMovementComponent() imposta il componente di movimento keyframe con valori basati su quelli che assegni nell'editor. Innanzitutto, crea una nuova variabile keyframed_movement_playback_mode per determinare la modalità di riproduzione utilizzata durante questa animazione. È inizializzata con il valore oneshot_keyframed_movement_playback_mode, il che significa che l'animazione verrà riprodotta una sola volta.
InitializeKeyframedMovementComponent(InKeyframedMovementComponent:keyframed_movement_component):void =
var PlaybackMode:keyframed_movement_playback_mode = oneshot_keyframed_movement_playback_mode{}Utilizza quindi un'istruzione case per impostare PlaybackMode in base al valore MovementMode impostato nell'editor. Ogni valore nell'enum MovementMode corrisponde a una diversa modalità di riproduzione definita nel modulo SceneGraph/KeyframedMovement.
case (MovementMode):
movement_mode.OneShot =>
set PlaybackMode = oneshot_keyframed_movement_playback_mode{}
movement_mode.Loop =>
set PlaybackMode = loop_keyframed_movement_playback_mode{}
movement_mode.PingPong =>
set PlaybackMode = pingpong_keyframed_movement_playback_mode{}Infine, la funzione imposta i keyframe e la modalità di movimento del componente di movimento con keyframe e l'animazione è ora pronta per essere riprodotta. Se la variabile AutoPlay è impostata su vero, l'animazione inizia immediatamente chiamando la funzione Play() del componente di movimento con fotogrammi keyframe.
InKeyframedMovementComponent.SetKeyframes(Keyframes, PlaybackMode)
if:
AutoPlay?
then:
InKeyframedMovementComponent.Play()Nell'editor, il componente simple_movement_component viene aggiunto all'entità Pivot e impostato con i valori seguenti. Ora, quando inizia il gioco, la lanterna inizia a oscillare avanti e indietro!
Script completo
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph/KeyframedMovement }
movement_mode<public> := enum:
OneShot
Loop
Interazione con la lanterna
La lanterna può oscillare avanti e indietro, ma avrai bisogno di un altro pezzo per permettere al tuo giocatore di interagire con essa. Puoi farlo collegando un componente non trattabile all'entità Lanterna e un lantern_interaction_component Verse personalizzato al lampione che ti permette di accendere e spegnere la lanterna.
Apri lo script LanternInteractionComponent.verse da Verse Explorer. Questo script inizia importando il modulo LightPost definito in Assets.digest.verse. Qui sono archiviati tutti gli asset relativi al lampione, per esempio il prefab. Importa anche il modulo LightPost.Materiali per accedere ai materiali e alle mesh del lampione e della lanterna.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
LightPost := module:
Materials<public> := module:
La classe lantern_interaction_component inizia definendo una variabile denominata MaterialInstance, che viene inizializzata su LightPost.Materials.MI_Lantern_01. Questa è l'istanza materiale che contiene tutte le variabili relative al materiale della lanterna.
lantern_interaction_component<public> := class<final_super>(component):
var MaterialInstance:LightPost.Materials.MI_Lantern_01 = LightPost.Materials.MI_Lantern_01{}In OnBeginSimulation(), lo script inizia trovando ogni componente delle sue entità discendenti con un interactable_component associato. Dato che lantern_interaction_component è collegato al lampione, questo restituirà interactable_component dell'entità Lanterna poiché è un discendente del lampione.
OnBeginSimulation<override>():void =
(super:)OnBeginSimulation()
InteractabeleComponents := Entity.FindDescendantComponents(interactable_component)Successivamente, in un'espressione for, lo script scorre ogni componente interagibile trovato e sottoscrive il relativo SucceededEvent alla funzione OnInteractFinished() definita più avanti in questo file. Ora, quando un giocatore termina di interagire con la lanterna, OnInteractFinished() verrà attivato.
InteractabeleComponents := Entity.FindDescendantComponents(interactable_component)
for (InteractableComponent : InteractabeleComponents):
InteractableComponent.SucceededEvent.Subscribe(OnInteractFinished)La funzione OnBeginSimulation() chiama quindi di nuovo FindDescendantComponents per trovare ogni entità a cui è collegato un componente LightPost.SM_Lightpost_Lantern_01. Questo è il componente mesh collegato alla lanterna. Poi imposta il componente mesh sulla MaterialInstance definita in precedenza, assicurando che la mesh della lanterna sia correttamente inizializzata.
MeshComponents := Entity.FindDescendantComponents(LightPost.SM_Lightpost_Lantern_01)
for (MeshComponent : MeshComponents):
set MeshComponent.M_Lantern = MaterialInstanceLa funzione OnInteractFinished() prende l'agente, o giocatore, come istigatore dell'interazione. Questa funzione chiama semplicemente la funzione ToggleLight() per accendere e spegnere la lanterna.
La funzione ToggleLight() fa il lavoro pesante in termini di accensione e spegnimento della lanterna. Innanzitutto, in un'espressione if, controlla se il livello di emissione di MaterialInstance è 0.0, a indicare che la luce è spenta. In caso affermativo, imposta il livello di emissione su 1.0. Quindi, in due espressioni for, trova ogni light_component e particle_system_component sulle entità discendenti e le attiva chiamando rispettivamente Enable() e Play().
ToggleLight():void =
if (MaterialInstance.Emissive_Multiply = 0.0):
set MaterialInstance.Emissive_Multiply = 1.0
for:
Light : Entity.FindDescendantComponents(light_component)
do:
Light.Enable()
for:
Se la luce era già accesa, la funzione fa il contrario all'interno dell'istruzione else. Imposta i livelli di emissione del materiale su 0.0 e disabilita tutti i componenti del sistema di luce e particella sulle entità discendenti.
else:
set MaterialInstance.Emissive_Multiply = 0.0
for:
Light : Entity.FindDescendantComponents(light_component)
do:
Light.Disable()
for:
Particle : Entity.FindDescendantComponents(particle_system_component)
Le funzioni di questo script si combinano per rendere dinamica la lanterna, accendendo e spegnendo più componenti quando un giocatore interagisce con essa. Tieni presente che mentre la lanterna è quella che viene accesa e spenta, l'entità del suo lampione genitore è quella che fornisce lantern_interaction_component.
Considera cosa dovresti fare per avere un lampione con più luci, accendendo e spegnendo ognuna di esse con la semplice pressione di un solo pulsante. Dato che questo codice opera trovando entità discendenti con un particolare tipo di componente, non è necessario un codice Verse aggiuntivo per implementare questa funzionalità. Se ogni entità lanterna figlio ha un componente luce o un componente particella, puoi procedere!
Script completo
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
LightPost := module:
Materials<public> := module: