Bisher haben wir Objekte sich bewegen, drehen oder skalieren lassen und alles drei gleichzeitig. Es gibt aber einige wichtige Herausforderungen, die berücksichtigt werden müssen, wenn Animationen für Props erstellt werden, die sich gleichzeitig auf verschiedene Arten bewegen.
Da der Animationscontroller nur jeweils eine Animation wiedergeben kann, kannst du nicht die Bewegung, Rotation und Drehung in separaten Animationen durchführen. Diese Animationen benötigen außerdem mehrere Keyframes, da du möglicherweise ein Prop mehrmals pro Animation drehen möchtest. Da du alle Keyframes vorab erstellen musst, musst du außerdem die Position, Rotation und Skalierung an jedem Punkt des Weges des Prop berechnen. Was passiert, wenn dein Prop keine gerade Anzahl von Drehungen durchführt? Wie gehst du mit einer halben Drehung um?
In dem nächsten Abschnitt kommt viel Mathematik vor, aber am Ende wirst du Props mit mehreren Punkten bewegen, drehen und skalieren können und komplex, dynamische und (vor allem!) lustige Plattform-Herausforderungen erstellen können, um den Fall-Guys-Kurs deiner Träume zu erstellen.
Erstellen von Animationen, die sich bewegen, drehen und skalieren
Befolge diese Schritte, um alles zusammenzubringen:
Erstelle mithilfe des Verse Explorer eine neue Verse-Klasse namens
animating_prop, die vonmovable_properbt. Füge den Bezeichner<concrete>zu dieser Klasse hinzu, um ihre Eigenschaften in UEFN freizugeben.Verse# A prop that translates, rotates, and scales to a destination using animation. animating_prop<public> := class<concrete>(movable_prop):Füge die Anweisungen
using { /Fortnite.com/Devices/CreativeAnimation }undusing { /UnrealEngine.com/Temporary/SpatialMath }oben in der Datei hinzu, um diese Module zu importieren. Du benötigst diese, um dein Prop zu animieren. Die in diesem Abschnitt verwendeten Tooltipps sind hier ebenfalls enthalten.Verseusing { /Fortnite.com/Devices } using { /Fortnite.com/Devices/CreativeAnimation } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/SpatialMath } RotationRateTip<localizes>:message := "The time it takes to make one AdditionalRotation in seconds." UseEasePerKeyframeTip<localizes>:message := "Whether this prop should use the MoveEaseType for each keyframe. False will use the Linear ease type on each frame." # A prop that translates, rotates, and scales to a destination using animation. animating_prop<public> := class<concrete>(movable_prop):Füge oben in der Klassendefinition von
animating_propdie folgenden Felder hinzu:Ein editable
rotationmit dem NamenAdditionalRotation. Dies ist die Drehung, die pro Keyframe auf dasRootPropangewendet werden soll.Verse# The additional rotation to apply to the RootProp per keyframe. @editable {ToolTip := AdditionalRotationTip} AdditionalRotation:rotation = rotation{}Ein editable
floatmit dem NamenRotationRate. Dies ist die Zeit in Sekunden, die für eineAdditionalRotationerforderlich ist.Verse# The time it takes to make one AdditionalRotation in seconds. @editable {ToolTip := RotationRateTip} var RotationRate:float = 1.0Ein editable
logicmit dem NamenUseEasePerKeyFrame. Dies gibt vor, ob jeder Keyframe denMoveEaseTypefür die Interpolation verwendet. Wenn dies in diesem Beispiel aufFalsefestgelegt wird, wird standardmäßig der lineare Interpolationstyp für jeden Frame verwendet.Verse# Whether this prop should use the MoveEaseType per each frame of animation. # Setting this to false will use the linear MoveEaseType on each frame. @editable UseEasePerKeyframe:logic = trueEin editable array von
creative_propmit dem NamenMoveTargets. Dies sind die verschiedenen Kreativmodus-Props, zu denen sich dein Stamm-Prop bewegt.Verse# The Creative prop target for the RootProp to move toward. @editable {ToolTip := MoveTargetsTip} var MoveTargets:[]creative_prop = array{}Eine Variable
transformmit dem NamenTargetTransform. Dies ist die Transformation, zu der sich dein Stamm-Prop aktuell bewegt.Verse# The transform the prop is currently targeting. var TargetTransform:transform = transform{}
Deine Klassendefinition sollte folgendermaßen aussehen:
Verseusing { /Fortnite.com/Devices } using { /Fortnite.com/Devices/CreativeAnimation } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/SpatialMath } RotationRateTip<localizes>:message := "The time it takes to make one AdditionalRotation in seconds." UseEasePerKeyframeTip<localizes>:message := "Whether this prop should use the MoveEaseType for each keyframe. False will use the Linear ease type on each frame." # A prop that translates, rotates, and scales to a destination using animation. animating_prop<public> := class<concrete>(movable_prop):Überschreibe die Funktion
Move()in deiner Klasseanimating_prop. Iteriere dann in einemfor-Ausdruck durch jedesMoveTargetim ArrayMoveTargets. Überprüfe, ob jedesMoveTargetgültig ist, und wenn ja, legeTargetTransformauf die Transformation desMoveTargetfest.Verse# Move and rotate the RootProp toward the MoveTarget, or MoveTransform if one is set. Move<override>()<suspends>:void= # Move to each target in the MoveTargets array. for: MoveTarget:MoveTargets do: # Set the TargetTransformto the MoveTarget if the # MoveTarget is set. Otherwise set it to the MoveTransform.Füge in der Datei
movement_behaviorseine neue Methode mit dem NamenBuildMovingAnimationKeyframes()hinzu. Diese Funktion erstellt ein Array mit Keyframes und gibt es zurück, das ein Prop animiert, das sich zu einer Zieltransformation bewegt und dreht. Diese Funktion erwartet mehrere Parameter vonanimating_prop–MoveDuration,RotationRate,AdditionalRotation,OriginalTransform(die Starttransformation des Prop),TargetTransform,MoveEaseType, und einen neuenlogic-Wert mit dem NamenUseEasePerKeyframe. Dies bestimmt, ob duMoveEaseTypefür jeden Keyframe verwendest. Deine Funktionssignatur sollte wie folgt aussehen:Verse# Builds an array of keyframes that animate movement and rotation from the OriginalTransform to the TargetTransform. BuildMovingAnimationKeyframes(MoveDuration:float, RotationRate:float, AdditionalRotation:rotation, OriginalTransform:transform, TargetTransform:transform,MoveEaseType:move_to_ease_type, UseEasePerKeyframe:logic):[]keyframe_delta=Initialisiere in
BuildMovingAnimationKeyframes()die folgenden Variablen:Ein Variablen-Array von
keyframe_deltamit dem NamenKeyframes. Dies ist das Array, das du am Ende zurückgibst.Verse# The array of keyframes to return. var KeyFrames:[]keyframe_delta = array{}Eine
float-Variable mit dem NamenTotalTime. Dies ist die Gesamtzeit, die bisher für die Animation angefallen ist.Verse# The total amount of time spent animating. var TotalTime:float = 0.0Zwei
transform-Variablen mit den NamenStartTransformundEndTransform. Dies sind die Start- und Endtransformationen des Prop zu Beginn und am Ende jedes Keyframe. Initialisiere beide mitOriginalTransform.Verse# The starting transform for building keyframes. This is the # transform of the RootProp at the start of each keyframe. var StartTransform:transform = OriginalTransform # The ending transform for building keyframes. This is the # transform of the RootProp at the end of each keyframe. var EndTransform:transform = OriginalTransformEine Variable
rotationmit dem NamenRotationToApply, initialisiert mitAdditionalRotation. Dies ist die tatsächliche Rotation, die du für jeden Keyframe auf das Prop anwendest. Normalerweise ist diesAdditionalRotation, aber wenn du eine Teildrehung durchführen musst, änderst du diesen Wert.Verse# The actual rotation to apply to the RootProp. Usually this is the # AdditionalRotation, but will change in cases with fractional rotations. var RotationToApply:rotation = AdditionalRotationEine
float-Variable mit dem NamenAnimationTime. Dies ist die Zeit in Sekunden, die jeder Keyframe benötigt. Initialisiere diese mit1.0 / RotationRate, da der RootProp eineRotationRate-Anzahl von Drehungen pro Sekunde ausführen muss.Verse# The time it takes for each keyframe of animation to complete. # This is initialized to 1.0/Rotation rate since the RootProp needs to make a # RotationRate number of rotations per second. var AnimationTime:float = 1.0 / RotationRateEinen
float-Wert mit dem NamenTotalRotations. Dies ist die Gesamtzahl der Drehungen, die während der gesamten Animation ausgeführt werden sollen, und wird mitMoveDuration * RotationRateinitialisiert. Dies ist einfloatund keinint, weil wir Situationen verarbeiten müssen, in denen keine vollständige Drehung erforderlich ist, wie zum Beispiel am Ende einer Animation.Verse# The total number of rotations to make. TotalRotations:float = MoveDuration * RotationRateEin
float-Wert mit dem NamenTimePerRotation. Dies ist die Zeit in Sekunden, die für den Abschluss einer Drehung erforderlich ist. Deine Funktion sollte nun wie folgt aussehen.Verse# Builds an array of keyframes that animate movement and rotation from the OriginalTransform to the TargetTransform. BuildMovingAnimationKeyframes(MoveDuration:float, RotationRate:float, AdditionalRotation:rotation, OriginalTransform:transform, TargetTransform:transform,MoveEaseType:move_to_ease_type, UseEasePerKeyframe:logic):[]keyframe_delta= # The array of keyframes to return. var KeyFrames:[]keyframe_delta = array{} # The total amount of time spent animating. var TotalTime:float = 0.0 # The starting transform for building keyframes. This is the
Das sind viele Werte, die wir im Auge behalten müssen. Erstellen wir also eine Beispielrechnung mit 2.5 als RotationRate und 5.0 als MoveDuration.
Rotation Rate = 2.5 rotations/second
Move Duration = 5.0 seconds
Animation Time =
1.0 seconds/Rotation Rate =
1.0/2.5 = 0.4 seconds
Total Rotations =
Move Duration /Rotation Rate =
Mit einer RotationRate von 2.5 und einer MoveDuration von 5.0 führst du insgesamt 12,5 Drehungen aus, wobei jede Drehung 0,4 Sekunden dauert. Das bedeutet, dass du am Ende der Animation eine zusätzliche halbe Drehung ausführen musst. Möglicherweise fällt dir auf, dass die Animationszeit und die Zeit pro Drehung identisch sind. Das ist fast immer der Fall, außer wenn weniger als eine vollständige Drehung erforderlich ist. Auch wenn sie anfangs dem gleichen Wert entsprechen, musst du beide Variablen verfolgen, um später entsprechende Mathematik anzuwenden.
Erstellen von Keyframes in einer Schleife
Zeit, endlich loszulegen! Folge den folgenden Schritten, um die Schleife einzurichten, die deine Keyframes erstellt.
Füge einen
loop-Ausdruck zuBuildMovingAnimationKeyframes()hinzu. Bei jeder Iteration über der Schleife erstellst du einen neuen Keyframe und fügst ihn zum Keyframes-Array hinzu. Aktualisiere am Anfang der Schleife dieTotalTimemitTimePerRotation.Verse# Build each keyframe of animation and add it to the Keyframes array. # The loop breaks when the TotalTime goes past the MoveDuration. loop: # Add the TimePerRotation to the TotalTime. set TotalTime += TimePerRotationErstelle
EndTransform, wo die Props am Ende dieses Keyframes sein sollen. LegeEndTransformauf eine neue Transformation mit den folgenden Parametern fest:Lege
Translationauf das Ergebnis des Aufrufs vonLerp()zwischenOriginalTransformundTargetTransformfest. Die FunktionLerp()nimmt zwei Werte und ein lineares Interpolationsverhältnis zwischen0.0und1.0an. Dann generiert sie basierend auf dem linearen Interpolationsverhältnis einen neuen Wert zwischen den beiden. Je näher das lineare Interpolationsverhältnis bei 1.0 liegt, desto näher befindet sich die Transformation anTargetTransformund umgekehrt.Verse# Build the ending transform for the RootProp to move to. set EndTransform = transform: # Use Lerp() to find how far between the StartingTransform and the TargetTransform the RootProp should translate. # Do the same for scale, and rotate the starting transform by the RotationToApply. # The Lerp Parameter is based on the total number of rotations since the RootProp should guarantee that it makes # at least that many rotations over the whole animation. Translation := Lerp(OriginalTransform.Translation, TargetTransform.Translation, (TotalTime * RotationRate) / (TotalRotations))Lege
Rotationauf das Ergebnis vonMakeShortestRotationBetween()fest, indem du die Drehung der ursprünglichen Transformation und die ursprüngliche Transformation, die umRotationToApplygedreht wurde, übergibst.VerseTranslation := Lerp(OriginalTransform.Translation, TargetTransform.Translation, (TotalTime * RotationRate) / (TotalRotations)) Rotation := MakeShortestRotationBetween(OriginalTransform.Rotation, OriginalTransform.Rotation.RotateBy(RotationToApply))~~~Lege
Scaleauf das Ergebnis des Aufrufs vonLerp()zwischenOriginalTransform.ScaleundTargetTransform.Scalefest. Berücksichtige, dass dies die Skalierung ist, auf die das Prop skalieren soll, nicht der Betrag, um den es skaliert werden muss. Dein fertigesEndTransformsollte wie folgt aussehen:Verse# Build the ending transform for the RootProp to move to. set EndTransform = transform: # Use Lerp() to find how far between the StartingTransform and the TargetTransform the RootProp should translate. # Do the same for scale, and find the shortest rotation between the original transform and a rotation to apply to it. Translation := Lerp(OriginalTransform.Translation, TargetTransform.Translation, LerpParameter) Rotation := MakeShortestRotationBetween(OriginalTransform.Rotation, OriginalTransform.Rotation.RotateBy(RotationToApply)) Scale := Lerp(OriginalTransform.Scale, TargetTransform.Scale, LerpParameter)
Nachdem deine Endtransformation festgelegt ist, kannst du einen Keyframe erstellen. Dies ist größtenteils der gleiche Prozess wie bei deiner Funktion
MoveToEase(). Erstelle eine neuekeyframe_delta-Variable mit dem NamenKeyFrame. LegeDeltaLocationauf die Differenz zwischen der End- und Start-Transformationsverschiebung fest. LegeDeltaRotationauf die Drehung der Endtransformation fest. Da du die Änderung der Skalierung berechnen musst, legst duDeltaScaleauf das Ergebnis der Division der Skalierung der Endtransformation durch die Skalierung der Starttransformation fest.TimesollteAnimationTimesein undInterpolationTypesollte das Ergebnis einesif-Ausdrucks sein. WennUseEasePerKeyframeTrue ist, verwendeMoveEaseType. Verwende andernfalls den linearen Typ. Dein Keyframe-Ausdruck sollte wie folgt aussehen:Verse# Build the animation keyframe to animate the RootProp. Keyframe := keyframe_delta: DeltaLocation := EndTransform.Translation - StartTransform.Translation, DeltaRotation := EndTransform.Rotation, DeltaScale := EndTransform.Scale/StartTransform.Scale, Time := AnimationTime, # Use the MoveEaseType for interpolation if UseEasePerKeyframe is true, # otherwise use the Linear movement type. Interpolation := if:Da du deinen Keyframe erstellt hast, kannst du ihn nun zum
Keyframes-Array hinzufügen. Lege dannStartTransformaufEndTransformfest, um es für den nächsten Keyframe zu aktualisieren. WennTotalTimenun größer alsMoveDurationist, verlasse die Schleife.Verse# Add the new keyframe to the KeyFrames array, and set the # StartTransform to the EndTransform. set Keyframes += array{Keyframe} set StartTransform = EndTransform # Break out of the loop if the TotalTime passes the MoveDuration. if: TotalTime >= MoveDuration then: breakEs ist ein wichtiger Sonderfall zu berücksichtigen: Was passiert, wenn du weniger als eine volle Umdrehung ausführen musst? Da du
TimePerRotationzuTotalTimehinzufügst, bedeutet dies, dassTotalTimezu Beginn der Schleife höher alsMoveDurationsein kann. In dieser Situation musst du die verbleibende Zeit verarbeiten und keine vollständige Drehung machen sowie eine kürzere Animationszeit verwenden, um die Differenz zu berücksichtigen. Befolge diese Schritte, um diese Situation zu berücksichtigen:Starte am Anfang der Schleife nach der Aktualisierung von
TotalTimeeinenif-Ausdruck. Initialisiere darin die VariableLeftoverTimeund lege sie gleich dem Ergebnis der Subtraktion vonTotalTimeundMoveDurationfest und prüfe, ob sie größer als0.0ist. Dieser Ausdruck weistLeftoverTimenur dann zu, wenn der Vergleich True ist.Verseloop: # Add the TimePerRotation to the TotalTime. set TotalTime += TimePerRotation if: # If the TotalTime is greater than the MoveDuration, the final keyframe needs # to be shortened. This means making a fraction of a rotation. LeftoverTime := TotalTime - MoveDuration > 0.0Um zu wissen, welche Teildrehung du machen musst, initialisiere eine neue Variable
RotationFraction, und lege sie gleich auf die Differenz zwischenTimePerRotationundLeftoverTimefest, alle geteilt durchTimePerRotation.Verseif: # If the TotalTime is greater than the MoveDuration, the final keyframe needs # to be shortened. This means making a fraction of a rotation. LeftoverTime := TotalTime - MoveDuration > 0.0 # The fraction of a rotation to make. RotationFraction := (TimePerRotation - LeftoverTime)/TimePerRotationUm eine veränderte Drehung aus
RotationFractionzu erstellen, verwendest duSlerp[]. Dies ist die Version vonLerp(), die eine sphärische Interpolation verarbeitet und ähnliche Parameter hat. Sie findet die kürzestes Drehung zwischen zwei verschiedenen Drehungen und gibt eine Drehung auf der Basis des Lerp-Parameters zurück. RufeSlerp[]auf, interpoliere zwischenIdentityRotation()undIdentityRotation()gedreht umRotationToApplyund verwendeRotationFractionals linearen Interpolationsparameter. Du verwendest hierIdentityRotation(), weil du nur herausfinden möchtest, welche Teildrehung du anwenden musst, nicht an welcher endgültigen Drehung sichEndTransformbefinden sollte.Verseset TotalTime += TimePerRotation if: # If the TotalTime is greater than the MoveDuration, the final keyframe needs # to be shortened. This means making a fraction of a rotation. LeftoverTime := TotalTime - MoveDuration > 0.0 # The fraction of a rotation to make. RotationFraction := (TimePerRotation - LeftoverTime)/TimePerRotation # Make a modified fractional rotation by using Slerp(). The Slerp() function does spherical interpolationNachdem diese Werte festgelegt sind, legst du
RotationToApplyaufModifiedRotationfest, multiplizierstAnimationTimemitRotationFraction, um zu wissen, um wie viel du deine Animation kürzen musst, und lege schließlichTotalTimeaufMoveDurationfest, da du nicht möchtest, dass es höher als das ist, wenn duEndTransformberechnest.VerseModifiedRotation := Slerp[IdentityRotation(), IdentityRotation().RotateBy(RotationToApply), RotationFraction] then: # Set the RotationToApply to the modified rotation, and multiply the animation time by # the RotationFraction to get the modified animation time. set RotationToApply = ModifiedRotation set AnimationTime = AnimationTime * RotationFraction # Since the TotalTime should not go past the MoveDuration, # set TotalTime to MoveDuration. set TotalTime = MoveDuration
Ganz am Ende deiner Funktion, nach der Schleife, gibst du das
Keyframes-Array zurück. Deine vollständigeBuildMovingAnimationKeyframes()-Funktion sollte wie folgt aussehen:Verse# Builds an array of keyframes that animate movement and rotation from the OriginalTransform to the TargetTransform. BuildMovingAnimationKeyframes(MoveDuration:float, RotationRate:float, AdditionalRotation:rotation, OriginalTransform:transform, TargetTransform:transform,MoveEaseType:move_to_ease_type, UseEasePerKeyframe:logic):[]keyframe_delta= # The array of keyframes to return. var Keyframes:[]keyframe_delta = array{} # The total amount of time spent animating. var TotalTime:float = 0.0 # The starting transform for building keyframes. This is theNachdem du nun die Logik zum Erstellen deiner Keyframes definiert hast, ist es an der Zeit, sie zu animieren. Du wirst eine separate Funktion verwenden, um deine Animation zu erstellen und aufzurufen. Füge eine neue Funktion
BuildAndPlayAnimation()zu deiner Klasseanimating_prophinzu. Füge den Modifikator<suspends>zu dieser Funktion hinzu, um ihr zu erlauben, andere asynchrone Funktionen aufzurufen.Verse# Builds an animation from an array of keyframes, then calls MoveToEase() # to animate the prop. BuildAndPlayAnimation()<suspends>:void=Initialisiere in
BuildAndPlayAnimation()ein neuesKeyframe_Delta-Array mit dem NamenKeyframes. LegeKeyframesdann auf das Ergebnis des Aufrufs vonBuildMovingAnimationKeyframes()fest. VerwendeRootProp.GetTransform()als anfängliche Transformation, da sich die Position der Props zwischen denMove()-Aufrufen ändern wird. Initialisiere eineanimation_mode-Variable mitanimation_mode.OneShotund rufeMoveToEase()auf. Übergib dasKeyframes-Array und denAnimationMode.Deine komplette
BuildAndPlayAnimation()-Funktion sollte wie folgt aussehen:Verse# Builds an animation from an array of keyframes, then calls MoveToEase() # to animate the prop. BuildAndPlayAnimation()<suspends>:void= var Keyframes:[]keyframe_delta = array{} # Build the animation, using the RootProp as the target transform. set Keyframes = BuildMovingAnimationKeyframes(MoveDuration, RotationRate, AdditionalRotation, RootProp.GetTransform(), TargetTransform, MoveEaseType, UseEasePerKeyframe) # Set the animation mode to OneShot. var AnimationMode:animation_mode := animation_mode.OneShotZurück in
Move(), rufeBuildAndPlayAnimation()auf, nachdem duTargetTransformauf die Transformation zum Ziel hierhin festgelegt hast.Verse# Move to each target in the MoveTargets array. for: MoveTarget:MoveTargets do: # Set the TargetTransform to the MoveTarget if the # MoveTarget is set. Otherwise set it to the MoveTransform. if: MoveTarget.IsValid[] then: set TargetTransform = MoveTarget.GetTransform()
Es gibt einen weiteren Fall, den wir berücksichtigen müssen. Was soll passieren, wenn wir keine Bewegungsziele festlegen? In dieser Situation soll sich dein Prop weiter an seiner Position drehen, ohne sich zu einem neuen Ziel zu bewegen. Um dies zu verarbeiten, füge einen if-Ausdruck am Anfang deiner Move()-Funktion hinzu. Prüfe im if-Ausdruck, ob MoveTargets.Length = 0 ist und lege TargetTransform auf die Transformation des Stamm-Props fest, wenn dies der Fall ist. Rufe dann BuildAndPlayAnimation() auf. Auf diese Art wird dein Prop weiterhin animiert, auch wenn du kein Bewegungsziel festgelegt hast. Deine komplette Move()-Animation sollte wie folgt aussehen:
# Move and rotate the RootProp toward the MoveTarget, or MoveTransform if one is set.
Move<override>()<suspends>:void=
# If there are no targets to move to, this prop will rotate in place.
if:
MoveTargets.Length = 0
then:
set TargetTransform = RootProp.GetTransform()
# Build and play the animation.
BuildAndPlayAnimation()
Jetzt musst du animating_prop in deiner Klasse prop_animator Klasse referenzieren. Füge in prop_animator ein bearbeitbares Array von animating_prop mit dem Namen MoveAndRotateProps hinzu. Initialisiere in OnBegin() in einem weiteren for-Ausdruck jedes Prop in MoveAndRotateProps, indem du Setup() aufrufst. Deine komplette Klasse prop_animator sollte wie folgt aussehen:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
TranslatingPropsTip<localizes>:message = "The props that translate (move) using animation."
RotatingPropsTip<localizes>:message = "The props that rotate using animation."
ScalingPropsTip<localizes>:message = "The props that scale using animation."
AnimatingPropsTip<localizes>:message = "The props that both move and rotate using animation."
# Coordinates moving props through animation by calling each movable_prop's Setup() method.
Speichere deinen Code und kompiliere ihn.
Herzlichen Glückwunsch, damit haben wir den gesamten Code abgehakt. Jetzt ist es an der Zeit, alles miteinander zu verbinden.
Die Klasse animating_prop, die du gerade erstellt hast, kann Props bewegen, drehen und skalieren. Sie ist aber noch abhängig von der Klasse moveable_prop, da sie verschiedene Funktionen wie ManageMovement() erben muss. Da die Klasse animating_prop alle drei Arten von Bewegungen ausführen kann, ist es möglicherweise hilfreich, animating_prop umzugestalten, um die gesamte Logik von moveable_prop einzubeziehen, sodass die Klasse eigenständig ist. Hier ist ein Beispiel für das Umgestalten enthalten, das animating_prop und moveable_prop in einer einzigen Datei zusammenführt. Es enthält auch die Verse-Geräteklasse prop_animator. Du benötigst aber noch immer die Funktionalität von movement_behaviors, damit dein Code ausgeführt werden kann, aber diese Umgestaltung reduziert die Anzahl der erforderlichen Dateien von fünf auf zwei. Dieser Code ist auch im Abschnitt Vollständiger Code enthalten.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
EasingCategory<localizes>:message := "These control the type of movement easing applied to the prop."
LogicCategory<localizes>:message := "These control different aspects of the prop's logic."
PropsCategory<localizes>:message := "These are the props that move associated with this device."
RotationCategory<localizes>:message := "These control how the prop rotates."
TimingCategory<localizes>:message := "These control the timing of parts of the prop's movmement."
Verbinden von Props mit Geräten
Lösche zurück im Editor einen Abschnitt des Kurses nach dem Abschnitt zum Drehen der Props, um eine Lücke vor dem Endziel zu erzeugen. Füge deinem Level einen weiteren FG01 SpinningBar Double S und FG01 Hover Platform M hinzu. Benenne sie SpinningMovingBar und TranslatingPlatform und füge dann mehrere FG01 Button Bulb Props hinzu, die die Ziele sind, zu denen sich jedes Prop bewegen wird. Benenne diese PlatformTarget. Platziere die Plattformen und den Balken über der Lücke und stelle sicher, dass du die Ziele dort platzierst, wohin sich die Plattformen bewegen sollen. In diesem Beispiel bewegt sich der drehende Balken seitwärts, während die Plattform sich vor und zurück bewegt.
Einrichtung des Drehbalkens und der beweglichen Plattform. Die Pfeile zeigen, in welche Richtungen sich das jeweilige Prop bewegt. Sowohl der Drehbalken als auch die Plattform bewegen sich vor und zurück, und der Drehbalken dreht sich bei der Bewegung.
Wähle deinen Prop-Animator im Outliner aus. Füge ein Array-Element zu AnimatingProps für deinen sich Drehbalken hinzu. Lege jeden Wert wie folgt fest:
| Option | Wert | Erklärung |
|---|---|---|
Zusätzliche Drehung | 90,0 | Dieses Prop macht jedes Mal eine 90-Grad-Drehung. |
Drehungsrate | 1.5 | Dieses Prop macht alle |
Verwende Ease pro Keyframe | false | Dies verwendet den linearen Easing-Typ für jeden Keyframe, um das Prop mit einer einheitlichen Geschwindigkeit zu bewegen und zu drehen. |
MoveTargets | 2 Elemente, die Plattformzielen zugewiesen sind. | Dies sind die Ziele, zu denen sich der Balken bewegen soll. |
RootProp | SpinningMovingBar | Dies ist das Prop, das du animierst. |
Füge für deine sich bewegende Plattform ein weiteres Array-Element zu TranslatingProps hinzu. Weise MoveTargets deinen Plattformzielen und RootProp der TranslatingPlatform zu.
Klicke auf Sitzung starten und versuche, deinen kompletten Hindernisparcours zu absolvieren!
Du bist am Zug
Und das war‘s schon! Du hast jetzt alles, was du benötigst, um deinen eigenen Fall-Guys-Hindernisparcours mit Verse zu erstellen.
Du kannst mit dem Code hier Kreativmodus-Props in jedem deiner Erlebnisse animieren und sogar über Fall-Guys-Projekte hinausgehen.
Probiere mit dem, was du gelernt hast, Folgendes aus:
Erstelle Hindernisse, die sich in verschiedene Richtungen drehen oder sich zufällig über Keyframes drehen.
Erstelle Hindernisse, die nur aktiviert werden, wenn ein Spieler darauf steht oder sich ihnen auf einen bestimmten Abstand nähert.
Überlege dir, wie du Plattformen erstellen kannst, die nach einer bestimmten Dauer verschwinden, oder wie du Spieler in gefährliche Positionen bewegst, wenn sie zu lange bleiben.
Vollständiger Code
Dies ist der vollständige Code, der in dieser Sektion erstellt wurde, einschließlich einer Beispiel-Umgestaltung für animating_prop.
movable_prop.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
MoveDurationTip<localizes>:message = "The amount of time the prop takes to move to its destination."
MoveEaseTypeTip<localizes>:message = "The animation easing applied to the movement."
MoveEndDelayTip<localizes>:message = "The delay after the movement finishes."
MoveOnceAndStopTip<localizes>:message = "Whether the RootProp should stop in place after it finishes moving."
MoveStartDelayTip<localizes>:message = "The delay before the movement starts."
MoveTargetsTip<localizes>:message = "The array of CreativeProp to move toward. These targets can be children of the RootProp."
translating_prop.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
MovePositionTip<localizes>:message = "The optional position to move to World Space. Use this if you do not want to set a MoveTarget."
# A prop that moves (translates) toward either a Creative prop target
# or a position in world space.
translating_prop<public> := class<concrete>(movable_prop):
rotating_prop.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
AdditionalRotationTip<localizes>:message = "The rotation to apply to the RootProp."
ShouldRotateForeverTip<localizes>:message = "Whether the RootProp should rotate forever."
MatchRotationTargetTip<localizes>:message = "The optional prop whose rotation the RootProp should rotate to. Use this if you do not want to set an Additional Rotation."
# A prop that rotates by an additional rotation or rotates to match
scaling_prop.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
MatchScaleTargetTip<localizes>:message = "The optional position to move to World Space. Use this if you do not want to set a MoveTarget."
# A prop that scales toward either a given scale or a Creative prop's scale.
scaling_prop<public> := class<concrete>(movable_prop):
# The array of vector3 targets for the RootProp to scale to.
animating_prop.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
RotationRateTip<localizes>:message := "The time it takes to make one AdditionalRotation in seconds."
UseEasePerKeyframeTip<localizes>:message := "Whether this prop should use the MoveEaseType for each keyframe. False will use the Linear ease type on each frame."
# A prop that translates, rotates, and scales to a destination using animation.
animating_prop<public> := class<concrete>(movable_prop):
movement_behaviors.verse
# This file stores functions common to animating Creative props using keyframes.
# It also defines the move_to_ease_type enum to help in building animations.
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Fortnite.com/Characters}
using { /Fortnite.com/Devices/CreativeAnimation }
# Represents the different movement easing types.
move_to_ease_type<public> := enum {Linear, Ease, EaseIn, EaseOut, EaseInOut}
prop_animator.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
TranslatingPropsTip<localizes>:message = "The props that translate (move) using animation."
RotatingPropsTip<localizes>:message = "The props that rotate using animation."
ScalingPropsTip<localizes>:message = "The props that scale using animation."
MoveAndRotatePropsTip<localizes>:message = "The props that both move and rotate using animation."
# Coordinates moving props through animation by calling each moveable_prop's Setup() method.
animating_props.verse (Beispiel-Umgestaltung von animating_prop)
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/CreativeAnimation }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
EasingCategory<localizes>:message := "These control the type of movement easing applied to the prop."
LogicCategory<localizes>:message := "These control different aspects of the prop's logic."
PropsCategory<localizes>:message := "These are the props that move associated with this device."
RotationCategory<localizes>:message := "These control how the prop rotates."
TimingCategory<localizes>:message := "These control the timing of parts of the prop's movmement."