Questa pagina ti guida attraverso la creazione di un nuovo componente Scene Graph denominato trigger_component. Questo attiva azioni sulle entità che hanno un componente Scene Graph che implementa l'interfaccia attivabile. trigger_component fornisce agli agenti un modo per interagire con Scene Graph attraverso un volume_device. Quando un agente entra o esce da volume_device, AgentEnteredEvent e AgentExitedEvent corrispondenti sono segnalati e i callback corrispondenti sono chiamati per eseguire azioni sui componenti e sulle entità Scene Graph.
Nell'immagine seguente, il piedistallo bianco sul terreno è un'entità Scene Graph con il trigger_component e un volume_device invisibile attorno al piedistallo.
Quando il giocatore sale sul piedistallo, il trigger_component attiva le due luci più lontane a destra.
Quando il giocatore scende dal piedistallo e lascia il volume_device, le luci rimangono nello stato acceso.
Per maggiori informazioni sulle funzioni del linguaggio Verse utilizzate in questa pagina, vedi:
Definisci il componente attivatore
Vai a Verse Explorer, fai clic con il pulsante destro del mouse sul nome del progetto e scegli Aggiungi nuovo file di Verse al progetto.
Scegli il modello Componente Scene Graph e modifica il Nome componente in trigger_component.
Definisci la
classetrigger_component e aggiungi i campi che fanno riferimento alvolume_deviceassociato, indipendentemente dal fatto che questo componente attivi solo figli o tutti i discendenti attivabili, e un array che faccia riferimento a tutti gli agenti che interagiscono col componente stesso.Versetrigger_component := class<final_super>(component): # volume_device associated with this trigger_component @editable InteractionVolume<private>:volume_device = volume_device{} # whether or not this triggers on components on child entities @editable OnlyTriggerChildren:logic = falseAggiungi funzioni denominate
OnAgentEntersVolumeeOnAgentExitsVolumeche definiscono cosa succede quando un agente entra ed esce dalvolume_deviceassociato a questo componente. Quando un agente entra nel volume, registra l'agente interagente e cerca le entità discendenti che hanno un componente che implementa l'interfacciaattivabile, quindi attiva il componente su quelle entità. Quando un agente entra nel volume, rimuovi l'agente interagente dall'elenco degli agenti che interagiscono con questo volume.Verse# Event that is triggered when an Agent enters the InteractionVolume OnAgentEntersVolume(Agent:agent):void= for: ChosenEntity : Entity.FindDescendantEntities(entity) ChosenEntityComponent : ChosenEntity.GetComponents() CastToInterface := triggerable[ChosenEntityComponent] do: if (OnlyTriggerChildren?): if (Entity = ChosenEntity.GetParent[]): CastToInterface.Trigger()Collega le funzioni
OnAgentEntersVolumeeOnAgentExitsVolumeavolume_deviceregistrandole come funzioni di callback perAgentEntersEventeAgentExitsEventnella funzioneOnSimulatedi questo componente.Verse# 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() # 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.
Definisci i componenti attivabili
Quindi, definisci i componenti che implementano l'interfaccia attivabile creata in precedenza. Si tratta di componenti aggiunti alle entità Scene Graph che sono discendenti di un'entità con un puzzle_component e sono attivati da un'entità antenata con un trigger_component. Questo tutorial definisce tre diversi componenti attivabili:
triggerable_mesh_component: attiva/disattiva la visibilità delmesh_componentdell'entità.triggerable_light_component: attiva/disattiva ilsphere_light_componentdell'entità e scambia ilmesh_componentdell'entità con uno con o senza colore emissivo, a seconda che la luce sia accesa o spenta.triggerable_movement_component: attiva una trasformazione delmesh_componentdell'entità utilizzando ilkeyframed_movement_component.
Questi tre diversi componenti condividono una grande funzionalità e molte funzioni sono definite allo stesso modo. Per iniziare, crea un nuovo file Verse vuoto denominato TriggerableComponents.verse.
Includi i seguenti moduli:
/Verse.org/SceneGraph poiché questo file utilizza i componenti Scene Graph e gli eventi di scena.
/Verse.org/SceneGraph/KeyframedMovement poiché questo file utilizza keyframed_movement_delta.
/Verse.org/Simulation poiché questo file utilizza l'attributo @editable.
/Verse.org/SpatialMath poiché questo file utilizza le trasformazioni di Verse.
Verseusing { /Verse.org/SceneGraph } using { /Verse.org/SceneGraph/KeyframedMovement } using { /Verse.org/Simulation } using { /Verse.org/SpatialMath }Definisci i componenti
triggerable_mesh_component,triggerable_light_componentetriggerable_movement_component. Tutti questi componenti ereditano dalla classe delcomponentedi base e implementano l'interfaccia attivabile.Tutti e tre i componenti implementano gli stessi tre eventi:
OnReceive: chiamato quando questo componente riceve un evento di scena.OnBeginSimulation: chiamato quando il componente deve iniziare la simulazione.OnSimulate: chiamato quando il componente inizia la simulazione.
Aggiungi le seguenti implementazioni a tutti e tre i componenti.
Verse# Runs when this component receives a scene event OnReceive<override>(SceneEvent:scene_event):logic= if (PuzzleSolvedEvent := puzzle_solved_event[SceneEvent], not PuzzlePiece?): Trigger() true false # Runs when the component should start simulating in a running game. OnBeginSimulation<override>():void = # Run OnBeginSimulation from the parent class beforeTutti e tre i componenti implementano anche l'override
PostTriggerdell'interfacciaattivabileallo stesso modo inviando untriggered_eventse il componenteattivabileè un pezzo di un puzzle. Non puoi eseguire questa operazione all'interno dell'interfacciaattivabilestessa perché Verse deve sapere qualeentitàè attivata; inoltre il campoentitàfa parte della classe delcomponentee non è disponibile per l'interfacciaattivabilesenza la dipendenza aggiuntiva dalla classe delcomponente.VersePostTrigger<override>():void = if (PuzzlePiece?): Event := triggered_event: Triggered := Triggered TriggeredEntity := option{Entity} Entity.SendUp(Event)
Componente mesh attivabile
Il triggerable_mesh_component attiva/disattiva la visibilità di un mesh_component su un'entità. È necessario dunque fornire gli override per le seguenti funzioni dell'interfaccia attivabili:
SetInitialTriggeredStatePerformActionPerformReverseAction
Lo stato iniziale attivato è determinato controllando se la mesh inizia o meno con l'essere visibile nel mondo di gioco come impostato nel pannello dettagli del componente mesh.
L'azione del
triggerable_mesh_componentè rendere visibile la mesh delmesh_component. Per eseguire questa operazione, recupera ilmesh_componentper l'entità corrispondente, imposta la mesh su visibile, quindi imposta iltriggerable_mesh_componentsullo stato attivato.Verse# Determine the initial triggered state of this component SetInitialTriggeredState<override>():void= if (MeshComponent := Entity.GetComponent[mesh_component], MeshComponent.Visible?): set Triggered = trueL'azione inversa per il
triggerable_mesh_componentè rendere invisibile la mesh delmesh_component. Per eseguire questa operazione, recupera ilmesh_componentper l'entità corrispondente, imposta la mesh su non visibile, quindi imposta iltriggerable_mesh_componentsullo stato non attivato.VersePerformReverseAction<override>():void = if (MeshComponent := Entity.GetComponent[mesh_component]): if (MeshComponent.Visible?): set MeshComponent.Visible = false set Triggered = false
Componente di movimento attivabile
Il triggerable_movement_component attiva un'entità per spostarsi da una posizione a una serie di altre posizioni in sequenza utilizzando il keyframed_movement_component. È necessario dunque fornire gli override per le seguenti funzioni dell'interfaccia attivabili:
SetInitialTriggeredStatePerformActionPerformReverseAction
Inoltre, questo componente utilizza alcune funzioni di supporto:
GetMovementStates: recupera le trasformazioni delle entità figlie che definiscono la serie di trasformazioni per questa entità.MakeDeltaTransform: crea una trasformazione delta tra due trasformazioni di input.ConstructKeyframeDeltas: crea un array di oggettikeyframed_movement_deltacome input per ilkeyframed_movement_component.SetAndPlayAnimation: assegna i keyframe e riproduci l'animazione del movimento.
Aggiungi un float modificabile a questa classe che determina la durata dell'animazione con keyframe.
Verse@editable Duration:float = 2.0Questa classe implementa l'interfaccia
attivabile, quindi è necessario fornire gli override per le funzioniPerformActionePerformReverseActionpoiché non hanno implementazioni predefinite. Poiché non esiste uno stato di attivazione iniziale e l'azione è un movimento tra posizioni, lo stato di attivazione iniziale predefinito è falso. Questo è ciò che fa l'implementazione di base nell'interfacciaattivabile, quindi questa funzione non richiede un override in questa classe di componenti.L'azione del
triggerable_movement_componentè spostare l'entità lungo la serie di trasformazioni definite dalle entità figlie.VersePerformAction<override>():void = MovementStates := GetMovementStates() AnimationFrames:[]keyframed_movement_delta = ConstructKeyframeDeltas(MovementStates) SetAndPlayAnimation(AnimationFrames)L'azione inversa del
triggerable_movement_componentè spostare l'entità lungo la serie di trasformazioni definite dalle entità figlie in ordine inverso. Questa funzione è simile aPerformAction, tranne per il fatto che l'array di trasformazione è in ordine inverso.VersePerformReverseAction<override>():void = MovementStates := GetMovementStates() ReversedMovementStates := for: Index := 0..MovementStates.Length - 1 ReversedElement := MovementStates[MovementStates.Length - 1 - Index] do: ReversedElement AnimationFrames := ConstructKeyframeDeltas(ReversedMovementStates) SetAndPlayAnimation(AnimationFrames)Definisci le funzioni di supporto utilizzate da questo componente. Innanzitutto, crea una funzione denominata
GetMovementStatesper recuperare le trasformazioni verso cui si sposta questo movimento.VerseGetMovementStates():[]transform= for (ChildEntity : Entity.FindDescendantEntities(entity), Entity = ChildEntity.GetParent[]): ChildEntity.GetGlobalTransform()Definisci una funzione di supporto denominata
MakeDeltaTransformche costruisce una trasformazione delta fra due trasformazioni. Una trasformazione delta, D, dalla trasformazione A alla trasformazione B è la trasformazione tale che quando la trasformazione D è applicata alla trasformazione A, il risultato è la trasformazione B.Per approfondire questo aspetto, supponiamo di avere un'entità Scene Graph con la trasformazione A corrente, ma di voler ridimensionare, ruotare e traslare l'entità per avere la trasformazione B. La trasformazione delta D è la trasformazione necessaria a un
keyframed_movement_deltaper animare il movimento dell'entità dalla trasformazione A alla trasformazione B.VerseMakeDeltaTransform(InTransformOne:transform, InTransformTwo:transform):transform = transform: Translation := InTransformTwo.Translation - InTransformOne.Translation Rotation := MakeComponentWiseDeltaRotation(InTransformOne.Rotation, InTransformTwo.Rotation) Scale := vector3: Forward := InTransformTwo.Scale.Forward / InTransformOne.Scale.Forward Right := InTransformTwo.Scale.Right / InTransformOne.Scale.Right Up := InTransformTwo.Scale.Up / InTransformTwo.Scale.UpDefinisci un support denominato
ConstructKeyframeDeltache crea un array di oggettikeyframed_movement_deltacome input per l'animazionekeyframed_movement_component.VerseConstructKeyframeDeltas<public>(MovementStates:[]transform):[]keyframed_movement_delta = var LastTransform:transform = Entity.GetGlobalTransform() for (EntityIndex -> CurrentTransform : MovementStates): DeltaTransform := MakeDeltaTransform(LastTransform, CurrentTransform) set LastTransform = CurrentTransform keyframed_movement_delta: Transform := DeltaTransform Duration := Duration Easing := if (MovementStates.Length > 1): if (EntityIndex = 0):Crea una funzione denominata
SetAndPlayAnimationche assegni l'arraykeyframed_movement_deltaall'animazionekeyframed_movement_componente la riproduca.VerseSetAndPlayAnimation<private>(Frames:[]keyframed_movement_delta):void = if (KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component]): KeyframedMovementComponent.SetKeyframes(Frames, oneshot_keyframed_movement_playback_mode{}) KeyframedMovementComponent.Play()
Componente luce attivabile
Il triggerable_light_component accende e spegne una luce. È necessario dunque fornire gli override per le seguenti funzioni dell'interfaccia attivabili:
SetInitialTriggeredStatePerformActionPerformReverseAction
Lo stato di attivazione iniziale della luce è determinato dal fatto che la luce sia accesa o meno, quindi
SetInitialTriggeredStatecontrolla se la luce è già accesa e, in caso affermativo, la imposta su attivata inizialmente.Verse# Determine the initial triggered state of this light SetInitialTriggeredState<override>():void= for: DescendantEntity : Entity.FindDescendantEntities(entity) Entity = DescendantEntity.GetParent[] MeshComponent := DescendantEntity.GetComponent[mesh_component] LightComponent := DescendantEntity.GetComponent[light_component] MeshComponent.IsEnabled[] LightComponent.IsEnabled[] do:L'azione eseguita dal
triggerable_light_componentè accendere la luce e passare a una mesh che indica che la luce è accesa.VersePerformAction<override>():void= if (not IsLightOn?): for (DescendantEntity:Entity.FindDescendantEntities(entity), Entity = DescendantEntity.GetParent[]): if (MeshComponent := DescendantEntity.GetComponent[mesh_component]): if (LightComponent := DescendantEntity.GetComponent[light_component]): MeshComponent.Enable() LightComponent.Enable() else: MeshComponent.Disable() set IsLightOn = trueL'azione eseguita dal
triggerable_light_componentè spegnere la luce e impostare ilmesh_componentnon emissivo su visibile.VersePerformReverseAction<override>():void= if (IsLightOn?): for (DescendantEntity:Entity.FindDescendantEntities(entity), Entity = DescendantEntity.GetParent[]): if (MeshComponent := DescendantEntity.GetComponent[mesh_component]): if (LightComponent := DescendantEntity.GetComponent[light_component]): MeshComponent.Disable() LightComponent.Disable() else: MeshComponent.Enable() set IsLightOn = false
Step successivi
Ora che tutto il codice Verse è stato scritto, compila il tuo codice Verse. Successivamente, costruisci prefab con entità e componenti di base che puoi riutilizzare in UEFN per creare la tua esperienza di puzzle.
Codice finale
TriggerComponent.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph }
using { Logging }
trigger_component<public> := class<final_super>(component):
@editable
InteractionVolume<private>:volume_device = volume_device{}
TriggerableComponents.verse
using { /Verse.org/SceneGraph }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
EnabledToolTip<public><localizes>:message = "Whether or not this component is enabled."
triggerable_mesh_component<public> := class<final_super>(component, triggerable):
<# Triggerable interface #>