Die Laternen im Scene Graph Tutorial verwenden zum Erstellen mehrere von Verse erstellte Komponenten dynamische und interaktive Prefabs. Das ist möglich, indem Bewegung und Interaktivität in eine von Verse erstellte Komponente programmiert werden.
Simulieren einfacher Bewegungen
Das Lichtpfahl-Prefab verwendet zwei unterschiedliche Komponenten, um das Bewegen der Laterne zu simulieren. Beide sind an die Drehpunkt-Entität angehängt, die einen Drehpunkt zum Bewegen der Laterne bietet. Zum einen erlaubt dir die keyframed_movement_component, Animationen aus Keyframes zu erstellen und sie dann abzuspielen, um eine Entität zu animieren. Diese Komponente kann jedoch nicht alleine agieren und benötigt ein weiteres Stück Code, um die Keyframes bereitzustellen und die Animation zu starten. Hier kommt die benutzerdefinierte simple_movement_component ins Spiel. Dieses Script wird im gesamten Projekt wiederverwendet, um zu steuern, wie sich verschiedene Spielobjekte in der Szene bewegen.
Sieh dir den Abschnitt Animating Prop Movement an, um mehr über das Verwenden von Animationen zum Bewegen von Objekten zu erfahren.
Sehen wir uns die simple_movement_component mal etwas genauer an. Öffne das Skript SimpleMovementComponent.verse aus dem Verse-Explorer in Visual Studio Code, um loszulegen.
Animationen nutzen verschiedene Wiedergabemodi, um zu definieren, was die Animation tun soll, wenn sie abgeschlossen ist. Diese werden oben in der Datei im Enum movement_mode definiert:
One-Shot – Das Objekt hört auf, sich zu bewegen, wenn es die Animation beendet.
Schleife – Das Objekt startet die Animation von Anfang an, wenn es das Ende erreicht.
Pin Pong – Das Objekt spielt die Animation umgekehrt ab, wobei es sich vom Anfang bis zum Ende vor und zurück bewegt.
movement_mode<public> := enum:
OneShot
Loop
PingPongDie Klasse basic_movement_component definiert auch Variablen, die zum Erstellen von Animationen benötigt werden. Jedes verfügt über das Attribut @editable, damit du sie im Outliner bearbeiten kannst:
Keyframes: Das Array vonkeyframed_movement_delta, das zum Erstellen der Animation verwendet wird. Jeder dieser Tracks verfolgt die Änderung der Transformation bei diesem bestimmten Keyframe, die Dauer des Keyframes und den Typ der verwendeten Bewegungs-Easing.AutoPlay: EineLogikvariable, die vorgibt, ob die Entität animieren soll, wenn sie mit der Simulation beginnt.MovementMode: Das Bewegungsverhalten, das die Entität zeigt
# 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
Der Code in OnSimulate() wird immer dann ausgeführt, wenn die Komponente zur Szene hinzugefügt wird und wenn das Spiel beginnt. Hier verwendet der Code zunächst einen kurzen Schlaf()-Aufruf, um sicherzustellen, dass alle Entitäten und Komponenten ordnungsgemäß initialisiert sind, bevor er fortfährt. Dann wird in einem if-Ausdruck geprüft, ob die Entität eine keyframed_movement_component hat.
Wenn dies der Fall ist, ruft sie die Funktion InitializeKeyFramedMovementComponent() auf, um die Komponente mit den richtigen Werten einzurichten. Was ist, wenn die Entität keine keyframed_movement_component hat? In diesem Fall kannst du eine dynamisch zur Laufzeit erstellen und sie mit der Funktion AddComponents() zur Entität hinzufügen. Auf diese Weise stellst du sicher, dass deine Entität richtig eingerichtet ist, wenn das Spiel beginnt!
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)Die Funktion InitializeKeyframedMovementComponent() legt die Keyframed-Bewegungskomponente mit Werten fest, die auf den Werten basieren, die du im Editor zuweisen. Zunächst wird eine neue Keyframed_movement_playback_mode-Variable erstellt, um den während dieser Animation verwendeten Wiedergabemodus zu bestimmen. Dies wird mit dem Wert oneshot_keyframed_movement_playback_mode initialisiert, was bedeutet, dass die Animation nur einmal abgespielt wird.
InitializeKeyframedMovementComponent(InKeyframedMovementComponent:keyframed_movement_component):void =
var PlaybackMode:keyframed_movement_playback_mode = oneshot_keyframed_movement_playback_mode{}Dann wird mit einer Fall-Anweisung der PlaybackMode basierend auf dem im Editor festgelegten MovementMode-Wert festgelegt. Jeder Wert in der Enum MovementMode entspricht einem anderen Wiedergabemodus, der im Modul SceneGraph/KeyframedMovement definiert ist.
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{}Schließlich setzt die Funktion die Keyframes und den Bewegungsmodus für die keyframebasierte Bewegungskomponente, und die Animation ist nun bereit zum Abspielen. Wenn die Variable AutoPlay auf True gesetzt ist, startet die Animation sofort durch den Aufruf der Spielen()-Funktion der Keyframe-Bewegungskomponente.
InKeyframedMovementComponent.SetKeyframes(Keyframes, PlaybackMode)
if:
AutoPlay?
then:
InKeyframedMovementComponent.Play()Zurück im Editor wird die simple_movement_component zur Pivot-Entität hinzugefügt und mit den folgenden Werten festgelegt. Wenn jetzt das Spiel beginnt, schwingt die Laterne hin und her!
Vollständiges Script
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
Interaktion mit der Laterne
Die Laterne kann hin und her schwanken, aber du brauchst ein weiteres Stück, damit dein Spieler damit interagieren kann. Dies geschieht, indem du eine Intractable-Komponente an die Laterne-Entität und eine benutzerdefinierte Verse- Laternte_interaction_component an den Lichtpfahl anhängst, mit der du die Laterne ein- und ausschalten kannst.
Öffne das LanternInteractionComponent.verse-Skript im Verse-Explorer. Dieses Script beginnt mit dem Importieren des in Assets.digest.verse definierten LightPost-Moduls. Hier werden alle Assets gespeichert, die sich auf den Lichtmast beziehen, z. B. das Prefab. Es importiert auch das Modul LightPost.Materials, um auf die Materialien und Meshs für den Lichtpfahl und die Laterne zuzugreifen.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
LightPost := module:
Materials<public> := module:
Die Klasse Laterne_Interaction_component definiert zunächst eine Variable mit dem Namen MaterialInstance, die mit LightPost.Materials.MI_Lantern_01 initialisiert wird. Dies ist die Material-Instanzierung, die alle Variablen enthält, die sich auf das Material der Laterne beziehen.
lantern_interaction_component<public> := class<final_super>(component):
var MaterialInstance:LightPost.Materials.MI_Lantern_01 = LightPost.Materials.MI_Lantern_01{}In OnBeginSimulation() beginnt das Skript damit, jede Komponente auf ihren Child-Entitäten mit einer angehängten interactable_component zu suchen. Da die Laternen_Interaction_component an den Lichtpfosten angehängt ist, gibt dies die interactable_component der Laternenentität zurück, da sie ein Child des Lichtpfahls ist.
OnBeginSimulation<override>():void =
(super:)OnBeginSimulation()
InteractabeleComponents := Entity.FindDescendantComponents(interactable_component)Als Nächstes iteriert das Script in einem for-Ausdruck durch jede gefundene interaktive Komponente und abonniert ihr SucceededEvent für die später in dieser Datei definierte Funktion OnInteractFinished(). Wenn nun ein Spieler die Interaktion mit der Laterne beendet, wird OnInteractFinished() ausgelöst.
InteractabeleComponents := Entity.FindDescendantComponents(interactable_component)
for (InteractableComponent : InteractabeleComponents):
InteractableComponent.SucceededEvent.Subscribe(OnInteractFinished)Die Funktion OnBeginSimulation() ruft dann erneut FindDescendantComponents auf, um jede Entität zu suchen, an die eine LightPost.SM_Lightpost_Lantern_01-Komponente angehängt ist. Dies ist die Netzkomponente, die an der Laterne befestigt ist. Es setzt dann die Mesh-Komponente auf die zuvor definierte MaterialInstance und stellt sicher, dass das Mesh der Laterne ordnungsgemäß initialisiert wird.
MeshComponents := Entity.FindDescendantComponents(LightPost.SM_Lightpost_Lantern_01)
for (MeshComponent : MeshComponents):
set MeshComponent.M_Lantern = MaterialInstanceDie Funktion OnInteractFinished() nimmt den Agenten oder Spieler als Auslöser (Signal) für die Interaktion. Diese Funktion ruft einfach die Funktion ToggleLight() auf, um die Laterne ein- und auszuschalten.
Die Funktion ToggleLight() erledigt die schwere Arbeit beim Ein- und Ausschalten der Laterne. Zunächst wird in einem if-Ausdruck geprüft, ob der emissive Level der MaterialInstance 0.0 ist, was bedeutet, dass das Licht ausgeschaltet ist. Ist dies der Fall, wird der Emissionslevel auf 1,0 gesetzt. Dann findet es in zwei for-Ausdrücken jede light_component und particle_system_component auf abhängigen Entitäten und aktiviert sie durch den Aufruf von Enable() bzw. 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:
Wenn das Licht bereits eingeschaltet war, führt die Funktion das Gegenteil innerhalb der else-Anweisung aus. Sie setzt die emissiven Materialstufen auf 0.0 und deaktiviert alle Licht- und Partikel Systemkomponente für untergeordnete Entitäten.
else:
set MaterialInstance.Emissive_Multiply = 0.0
for:
Light : Entity.FindDescendantComponents(light_component)
do:
Light.Disable()
for:
Particle : Entity.FindDescendantComponents(particle_system_component)
Die Funktionen in diesem Script werden kombiniert, um die Laterne dynamisch zu machen und mehrere Komponenten ein- und auszuschalten, wenn ein Spieler mit ihr interagiert. Beachte, dass während die Laterne ein- und ausgeschaltet wird, ihre Parent-Lichtpfahl-Entität die lantern_interaction_component bereitstellt.
Überlege, was du tun müsstest, um einen Lichtmast mit mehreren Lichtern zu haben, die sich jeweils mit einem Druck auf eine einzige Schaltfläche ein- und ausschalten lassen. Da dieser Code durch die Suche von Descendant-Entitäten mit einem bestimmten Komponententyp arbeitet, brauchst du keinen zusätzlichen Verse-Code, um diese Funktionalität zu implementieren. Solange jede Child-Laternenentität eine Lichtkomponente oder eine Partikelkomponente hat, kannst du loslegen!
Vollständiges Script
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
LightPost := module:
Materials<public> := module: