Diese Seite führt dich durch die Erstellung einer neuen Scene-Graph-component mit dem Namen trigger_component. Diese Komponente löst Aktionen für entities aus, die über eine Scene-Graph-Komponente verfügen, die das triggerable-Interface implementiert. Die trigger_component bietet Agents eine Möglichkeit, über ein volume_device mit Scene Graph zu interagieren. Wenn ein Agent das volume_device betritt oder verlässt, wird das entsprechende AgentEnteredEvent und AgentExitedEvent signalisiert und entsprechende Callbacks werden aufgerufen, um Actions für Scene-Graph-Komponenten und -Entitäten durchzuführen.
In dem folgenden Bild ist der weiße Sockel auf dem Boden eine Scene-Graph-Entität mit der trigger_component und einem unsichtbaren volume_device um den Sockel herum.
Wenn der Spieler auf den Sockel tritt, löst die trigger_component die beiden Lichter ganz rechts aus.
Wenn der Spieler vom Sockel tritt und das volume_device verlässt, bleiben die Lichter im eingeschalteten Zustand.
Mehr Informationen zu den auf dieser Seite verwendeten Verse-Sprachfunktionen findest du unter:
Trigger-Komponente definieren
Navigiere zum Verse-Explorer, klicke mit der rechten Maustaste auf den Projektnamen und wähle Neue Verse-Datei zum Projekt hinzufügen.
Wähle die Vorlage Scene-Graph-Komponente aus und ändere Komponentenname in trigger_component.
Definiere die
trigger_component-class und füge Felder hinzu, die auf das zugehörigevolume_deviceverweisen, unabhängig davon, ob diese Komponente nur Children oder alle auslösbaren Descendants auslöst, und ein Array, das auf alle agents verweist, die mit dieser Komponente interagieren.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 = falseFüge die Funktionen
OnAgentEntersVolumeundOnAgentExitsVolumehinzu, die definieren, was passiert, wenn ein Agent das zugehörigevolume_devicedieser Komponente betritt und verlässt. Wenn ein Agent das Volumen betritt, wird der interagierende Agent aufgezeichnet und nach Child-Entitäten gesucht, die eine Komponente haben, die dastriggerable-Interface implementiert, und dann die Komponente für diese Entitäten auslösen. Wenn ein Agent das Volumen betritt, entferne den interagierenden Agenten aus der Liste der Agents, die mit diesem Volumen interagieren.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()Verbinde die Funktionen
OnAgentEntersVolumeundOnAgentExitsVolumemit demvolume_device, indem du sie als Callback-Funktionen fürAgentEntersEventundAgentExitsEventin derOnSimulate-Funktion dieser Komponente registrierst.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.
Die auslösbaren Komponenten definieren
Als nächstes definierst du Komponenten, die das zuvor erstellte triggerable Interface implementieren. Dies sind Komponenten, die zu Scene-Graph-Entitäten hinzugefügt werden, die Descendants einer Entität mit einer puzzle_component sind, und von einer Ancestor-Entität mit einer trigger_component ausgelöst werden. Dieses Tutorial definiert drei verschiedene triggerable-Komponenten:
triggerable_mesh_component: Schaltet die Sichtbarkeit dermesh_componentder Entität um.triggerable_light_component: Schaltet diesphere_light_componentder Entität ein und aus und tauscht diemesh_componentder Entität gegen eine mit oder ohne emissive-Farbe aus, je nachdem, ob das Licht an oder aus ist.triggerable_movement_component: Löse eine Transformation dermesh_componentder Entität unter Verwendung derkeyframed_movement_componentaus.
Diese drei verschiedenen Komponenten teilen einen großen Teil der Funktionalität, und viele der Funktionen sind auf die gleiche Weise definiert. Erstelle zunächst eine neue, leere Verse-Datei namens TriggerableComponents.verse.
Füge die folgenden Module hinzu:
/Verse.org/SceneGraph, da diese Datei Scene-Graph-Komponenten und Szenen-Events verwendet.
/Verse.org/SceneGraph/KeyframedMovement, da diese Datei keyframed_movement_delta verwendet.
/Verse.org/Simulation hinzufügen, da diese Datei das Attribut @editable verwendet.
/Verse.org/SpatialMath hinzufügen, da diese Datei Verse-Transformationen verwendet.
Verseusing { /Verse.org/SceneGraph } using { /Verse.org/SceneGraph/KeyframedMovement } using { /Verse.org/Simulation } using { /Verse.org/SpatialMath }Definiere die Komponenten
triggerable_mesh_component,triggerable_light_componentundtriggerable_movement_component. Alle diese Komponenten erben von dercomponent-Basisklasse und implementieren das triggerable-Interface.Alle drei Komponenten implementieren die gleichen drei Events:
OnReceive: Wird aufgerufen, wenn diese Komponente ein Szenen-Event empfängt.OnBeginSimulation: Wird aufgerufen, wenn die Komponente mit der Simulation beginnen soll.OnSimulate: Wird aufgerufen, wenn die Komponente mit der Simulation beginnt.
Füge die folgenden Implementierungen zu allen drei Komponenten hinzu.
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 beforeAlle drei Komponenten implementieren auch den
PostTrigger-Override destriggerable-Interfaces auf die gleiche Weise, indem sie eintriggered_eventsenden, wenn dietriggerable-Komponente ein Puzzleteil ist. Du kannst dies nicht innerhalb destriggerable-Interfaces selbst erreichen, weil Verse wissen muss, welcheentityausgelöst wird, und dasEntity-Feld ist Teil dercomponentklasse und für dastriggerable-Interface ohne die zusätzliche Abhängigkeit von dercomponent-Klasse nicht verfügbar.VersePostTrigger<override>():void = if (PuzzlePiece?): Event := triggered_event: Triggered := Triggered TriggeredEntity := option{Entity} Entity.SendUp(Event)
Auslösbare Mesh-Komponente
Die triggerable_mesh_component schaltet die Sichtbarkeit einer mesh_component auf einer Entität um. Das erfordert die Bereitstellung von Overrides für die folgenden triggerable-Interface-Funktionen:
SetInitialTriggeredStatePerformActionPerformReverseAction
Der anfänglich ausgelöste Zustand wird bestimmt, indem geprüft wird, ob das Mesh in der Spielwelt so sichtbar beginnt, wie es im Details-Panel der Mesh-Komponente festgelegt ist.
Die Aktion für die
triggerable_mesh_componentbesteht darin, das Mesh dermesh_componentsichtbar zu machen. Dazu rufst du diemesh_componentfür die entsprechende Entität ab, setzt das Mesh auf sichtbar und dann dietriggerable_mesh_componentauf den ausgelösten Zustand.Verse# Determine the initial triggered state of this component SetInitialTriggeredState<override>():void= if (MeshComponent := Entity.GetComponent[mesh_component], MeshComponent.Visible?): set Triggered = trueDie umgekehrte Aktion für die
triggerable_mesh_componentbesteht darin, das Mesh dermesh_componentunsichtbar zu machen. Dazu rufst du diemesh_componentfür die entsprechende Entität ab, setzt das Mesh auf nicht sichtbar und dann dietriggerable_mesh_componentauf den nicht ausgelösten Zustand.VersePerformReverseAction<override>():void = if (MeshComponent := Entity.GetComponent[mesh_component]): if (MeshComponent.Visible?): set MeshComponent.Visible = false set Triggered = false
Auslösbare Bewegungskomponente
Die triggerable_movement_component veranlasst eine Entität dazu, sich von einem Standort aus nacheinander an eine Reihe von anderen Orten zu bewegen, indem sie den keyframed_movement_component verwendet. Das erfordert die Bereitstellung von Overrides für die folgenden triggerable-Interface-Funktionen:
SetInitialTriggeredStatePerformActionPerformReverseAction
Darüber hinaus verwendet diese Komponente einige Hilfsfunktionen:
GetMovementStates: Rufe die Transformationen von Child-Entitäten ab, die die Reihe von Transformationen für diese Entität definieren.MakeDeltaTransform: Erstelle eine Delta-Transformation zwischen zwei Input-Transformationen.ConstructKeyframeDeltas: Erstelle ein Array vonkeyframed_movement_delta-Objekten als Input für diekeyframed_movement_component.SetAndPlayAnimation: Weist die Keyframes zu und gibt die Bewegungsanimation wieder.
Füge einen bearbeitbaren float zu dieser Klasse hinzu, der bestimmt, wie lange die Keyframe-Animation dauert.
Verse@editable Duration:float = 2.0Diese Klasse implementiert das
triggerable-Interface, daher müssen Overrides für die FunktionenPerformActionundPerformReverseActionbereitgestellt werden, da sie keine Standardimplementierungen haben. Da es keinen anfänglich ausgelösten Zustand gibt und die Action eine Bewegung zwischen Orten ist, ist der standardmäßige anfänglich ausgelöste Zustand False. Das ist die Funktion der Basisimplementierung imtriggerable-Interface, sodass für diese Funktion kein Override in dieser Komponentenklasse erforderlich ist.Die Action für die
triggerable_movement_componentbesteht darin, die Entität entlang der Reihe von Transformationen zu bewegen, die durch Child-Entitäten definiert sind.VersePerformAction<override>():void = MovementStates := GetMovementStates() AnimationFrames:[]keyframed_movement_delta = ConstructKeyframeDeltas(MovementStates) SetAndPlayAnimation(AnimationFrames)Die umgekehrte Action für die
triggerable_movement_componentbesteht darin, die Entität entlang der Reihe von Transformationen zu bewegen, die durch Child-Entitäten in umgekehrter Reihenfolge definiert sind. Diese Funktion ist derPerformActionähnlich, mit dem Unterschied, dass das Transformation-Array die umgekehrte Reihenfolge hat.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)Definiere die Hilfsfunktionen, die diese Komponente verwendet. Erstelle zunächst eine Funktion namens
GetMovementStates, um die Transformationen abzurufen, zu denen sich diese Bewegung bewegt.VerseGetMovementStates():[]transform= for (ChildEntity : Entity.FindDescendantEntities(entity), Entity = ChildEntity.GetParent[]): ChildEntity.GetGlobalTransform()Definiere eine Hilfsfunktion namens
MakeDeltaTransform, die eine Delta-Transformation zwischen zwei Transformationen erstellt. Eine Delta-Transformation, D, von Transformation A zu Transformation B ist die Transformation, so dass, wenn Transformation D auf Transformation A angewendet wird, das Ergebnis Transformation B ist.Um dies zu verdeutlichen, nimm an, dass du eine Scene-Graph-Entität mit der aktuellen Transformation A hast, aber du möchtest deine Entität skalieren, drehen und verschieben, um Transformation B zu haben. Die Delta-Transformation D ist die Transformation, die du für ein
keyframed_movement_deltabenötigst, um die Bewegung deiner Entität von Transformation A zu Transformation B zu animieren.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.UpDefiniere eine Hilfsfunktion namens
ConstructKeyframeDelta, die ein Array vonkeyframed_movement_delta-Objekten als Eingabe für diekeyframed_movement_component-Animation erstellt.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):Erstelle eine Funktion namens
SetAndPlayAnimation, die das Arraykeyframed_movement_deltader Animationkeyframed_movement_componentzuweist und sie abspielt.VerseSetAndPlayAnimation<private>(Frames:[]keyframed_movement_delta):void = if (KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component]): KeyframedMovementComponent.SetKeyframes(Frames, oneshot_keyframed_movement_playback_mode{}) KeyframedMovementComponent.Play()
Auslösbare Licht-Komponente
Die triggerable_light_component schaltet ein Licht ein und aus. Das erfordert die Bereitstellung von Overrides für die folgenden triggerable-Interface-Funktionen:
SetInitialTriggeredStatePerformActionPerformReverseAction
Der anfänglich ausgelöste Zustand des Lichts wird davon bestimmt, ob das Licht eingeschaltet ist oder nicht.
SetInitialTriggeredStateprüft also, ob das Licht bereits eingeschaltet ist, und wenn dies der Fall ist, wird es auf anfänglich ausgelöst gesetzt.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:Die von der
triggerable_light_componentdurchgeführte Action besteht darin, das Licht einzuschalten und zu einem Mesh zu wechseln, das anzeigt, dass das Licht eingeschaltet ist.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 = trueDie von der
triggerable_light_componentdurchgeführte Action besteht darin, das Licht auszuschalten und die nicht emissivemesh_componentsichtbar zu machen.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
Nächste Schritte
Nachdem jetzt der gesamte Verse-Code geschrieben wurde, erstelle deinen Verse-Code. Konstruiere als nächstes Prefabs mit Basis-Entitäten und Komponenten, die du in UEFN wiederverwenden kannst, um dein Rätsel-Erlebnis zu erstellen.
Endgültiger Code
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 #>