Gdy mamy już obiekty, które się poruszają, obracają lub skalują, kolejnym krokiem jest połączenie wszystkich tych efektów razem. Tworzenie animacji rekwizytów, które poruszają się jednocześnie na różne sposoby, wiąże się z nowymi wyzwaniami.
Kontroler animacji może odtworzyć tylko jedną animację w danym momencie, dlatego nie możesz wykonać ruchu, obrotu i skalowania w oddzielnych animacjach. Te animacje potrzebują również wielu klatek kluczowych, ponieważ możesz chcieć obrócić rekwizyt wiele razy w trakcie każdej animacji. Wszystkie klatki kluczowe musisz utworzyć z wyprzedzeniem, dlatego trzeba też obliczyć pozycję, obrót i skalę w każdym punkcie drogi rekwizytu. Co się stanie, jeśli rekwizyt nie wykona parzystej liczby obrotów? Jak zrealizować pół obrotu?
W kolejnej sekcji będzie dużo matematyki. Na koniec jednak będziesz poruszać rekwizytami, obracać je i skalować do wielu punktów oraz kreować złożone, dynamiczne i (co najważniejsze!) atrakcyjne wyzwania platformowe, aby utworzyć tor Fall Guys, jaki ci się zamarzy.
Budowanie animacji, które się poruszają, obracają i skalują
Wykonaj poniższe kroki, aby zacząć łączyć wszystko razem:
Utwórz nową klasę Verse o nazwie
animating_prop, która dziedziczy zmovable_propprzy użyciu Eksploratora Verse. Do tej klasy dodaj specyfikator<concrete>, aby uwidocznić jej właściwości dla UEFN.Verse# A prop that translates, rotates, and scales to a destination using animation. animating_prop<public> := class<concrete>(movable_prop):Dodaj instrukcje
using { /Fortnite.com/Devices/CreativeAnimation }iusing { /UnrealEngine.com/Temporary/SpatialMath }na początku pliku, aby zaimportować te moduły. Są one potrzebne, aby animować rekwizyt. W tym miejscu dołączono podpowiedzi użyte w tej sekcji.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):Na początku definicji klasy
animating_propdodaj następujące pola:Edytowalny
obróto nazwieAdditionalRotation. Jest to obrót, który ma być zastosowany doRootPropna każdą klatkę kluczową.Verse# The additional rotation to apply to the RootProp per keyframe. @editable {ToolTip := AdditionalRotationTip} AdditionalRotation:rotation = rotation{}Edytowalna
wartość zmiennopozycyjnao nazwieRotationRate.Jest to wyrażona w sekundach ilość czasu, przez jaką trwa wykonanie jednegoAdditionalRotation.Verse# The time it takes to make one AdditionalRotation in seconds. @editable {ToolTip := RotationRateTip} var RotationRate:float = 1.0Edytowalna
wartość logicznao nazwieUseEasePerKeyFrame. Określa to, czy każda klatka kluczowa do interpolacji używaMoveEaseType. W tym przykładzie ustawienie tej opcji nafalsespowoduje, że domyślnie dla każdej klatki będzie używany liniowy typ interpolacji.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 = trueEdytowalna tablica
creative_propo nazwieMoveTargets. Istnieją różne rekwizyty Trybu kreatywnego, w których kierunku będzie się przemieszczał rekwizyt główny.Verse# The Creative prop target for the RootProp to move toward. @editable {ToolTip := MoveTargetsTip} var MoveTargets:[]creative_prop = array{}Przekształceniezmiennejo nazwie TargetTransform . Jest to przekształcenie, do którego aktualnie dąży rekwizyt nadrzędny.Verse# The transform the prop is currently targeting. var TargetTransform:transform = transform{}
Definicja klasy powinna wyglądać następująco:
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):Zastąp funkcję
Move()w klasieanimating_prop. Następnie w wyrażeniuforwykonaj iterację przez każdyMoveTargetw tablicyMoveTargets. Sprawdź, czy każdyMoveTargetjest prawidłowy, a jeśli tak, ustawTargetTransformna przekształcenieMoveTarget.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.Wróć do pliku
movement_behaviorsi dodaj do niego nową metodę o nazwieBuildMovingAnimationKeyframes(). Ta funkcja utworzy i zwróci tablicę klatek kluczowych, które animują rekwizyt, poruszając nim i obracając go do przekształcenia docelowego. Ta funkcja przyjmuje kilka parametrów zanimating_prop–MoveDuration,RotationRate,AdditionalRotation,OriginalTransform(przekształcenie początkowe rekwizytu),TargetTransform,MoveEaseTypei nowąwartość logicznąo nazwieUseEasePerKeyframe. Określa to, czy dla każdej klatki kluczowej używaszMoveEaseType. Sygnatura funkcji powinna wyglądać następująco: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=W
BuildMovingAnimationKeyframes(), inicjowanie następujących zmiennych:Tablica
keyframe_deltazmiennej o nazwieKeyframes. Jest to tablica, którą zwrócisz na końcu.Verse# The array of keyframes to return. var KeyFrames:[]keyframe_delta = array{}Wartość zmiennopozycyjnazmiennej o nazwieTotalTime. Łączna ilość czasu poświęcona na animację do danego momentu.Verse# The total amount of time spent animating. var TotalTime:float = 0.0Dwie zmienne
transformo nazwachStartTransformiEndTransform. Są to początkowe i końcowe przekształcenia rekwizytu na początku i na końcu każdej klatki kluczowej. Zainicjuj obie naOriginalTransform.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 = OriginalTransformObrótzmiennej o nazwieRotationToApply, zainicjowany naAdditionalRotation. Jest to faktyczny obrót, który będzie zastosowany do rekwizytu dla każdej klatki kluczowej. Zwykle będzie toAdditionalRotation, ale jeśli potrzebujesz obrotu ułamkowego, zmień tę wartość.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 = AdditionalRotationWartość zmiennopozycyjnazmiennej o nazwieAnimationTime. Czas trwania każdej klatki kluczowej w sekundach. Zainicjuj na1.0 / RotationRate, ponieważ RootProp musi wykonać liczbę obrotów na sekundę równąRotationRate.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 / RotationRateWartość zmiennopozycyjnao nazwieTotalRotations. Jest to łączna liczba obrotów, które mają być wykonane w trakcie całej animacji, zainicjowana naMoveDuration * RotationRate. Dzieje się tak dlatego, że w sytuacjach, w których nie trzeba wykonywać całego obrotu, np. na końcu animacji, używa się wartościfloat, a nieint.Verse# The total number of rotations to make. TotalRotations:float = MoveDuration * RotationRateWartość zmiennopozycyjnao nazwieTimePerRotation. Czas wykonania jednego pełnego obrotu w sekundach. Funkcja powinna wyglądać następująco: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
Trzeba pamiętać o wielu wartościach, dlatego wykonajmy przykładowe obliczenie, używając 2.5 jako RotationRate i 5.0 jako 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 =
Z RotationRate 2.5 i MoveDuration 5.0, wykonasz w sumie 12.5 obrotu, przy czym każdy obrót zajmie 0.4 sekundy. Oznacza to, że trzeba będzie dodać dodatkowe pół obrotu na końcu animacji. Zwróć uwagę, że czas animacji i czas na każdy obrót są takie same. Dzieje się tak prawie zawsze, z wyjątkiem sytuacji, w których trzeba wykonać mniej niż pełny obrót. Początkowo mają tę samą wartość, ale trzeba śledzić obie zmienne, aby później wykonać pewne obliczenia matematyczne.
Budowanie klatek kluczowych w pętli
Czas rozpocząć budowanie! Wykonaj poniższe kroki, aby skonfigurować pętlę, która tworzy klatki kluczowe.
Dodaj wyrażenie
loop(pętla) doBuildMovingAnimationKeyframes(). Przy każdym powtórzeniu pętli zbudujesz nową klatkę kluczową i dodasz ją do tablicy klatek kluczowych. Na początku pętli zaktualizujTotalTimeoTimePerRotation.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 += TimePerRotationSkompiluj
EndTransform, czyli miejsce, w którym rekwizyt powinien znajdować się na końcu tej klatki kluczowej. UstawEndTransformna nowe przekształcenie z następującymi parametrami:Ustaw
Translationna wynik wywołaniaLerp()międzyOriginalTransformiTargetTransform. FunkcjaLerp()przyjmuje dwie wartości i współczynnik Lerp pomiędzy0.0a1.0. Następnie generuje nową wartość z zakresu między dwiema wartościami na podstawie współczynnika Lerp. Im współczynnik Lerp jest bliższy 1.0, tym bliższe będzie przekształcenieTargetTransformi odwrotnie.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))Ustaw
Rotationna wynikMakeShortestRotationBetween(), przekazując obrót początkowego przekształcenia oraz początkowe przekształcenie obrócone o wartośćRotationToApply.VerseTranslation := Lerp(OriginalTransform.Translation, TargetTransform.Translation, (TotalTime * RotationRate) / (TotalRotations)) Rotation := MakeShortestRotationBetween(OriginalTransform.Rotation, OriginalTransform.Rotation.RotateBy(RotationToApply))~~~Ustaw metodę
Scalena wynik wywołaniaLerp()międzyOriginalTransform.ScaleiTargetTransform.Scale. Pamiętaj, że jest to skala, do której rekwizyt ma się przeskalować, a nie wielkość, o jaką ma być przeskalowany. Gotowy kodEndTransformpowinien wyglądać następująco: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)
Po ustawieniu przekształcenia końcowego czas utworzyć klatkę kluczową! Zasadniczo proces jest taki sam, jak w przypadku funkcji
MoveToEase(). Utwórz nową zmiennąkeyframe_deltao nazwieKeyFrame. UstawDeltaLocationna różnicę między translacjami przekształcenia końcowego i początkowego. UstawDeltaRotationna obrót przekształcenia końcowego. Musisz obliczyć zmianę skali, dlatego ustawDeltaScalena iloraz skali przekształcenia końcowego i skali przekształcenia początkowego. WartośćTimepowinna być wartościąAnimationTime, a wartośćInterpolationTypepowinna być wynikiem wyrażeniaif. JeśliUseEasePerKeyframema wartość true, użyjMoveEaseType. W przeciwnym razie użyj typu liniowego. Wyrażenie klatki kluczowej powinno wyglądać następująco: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:Po utworzeniu klatki kluczowej możesz dodać ją do tablicy
klatek kluczowych. Następnie ustawStartTransformnaEndTransform, aby zaktualizować go dla następnej klatki kluczowej. Na koniec, jeśliTotalTimejest teraz większe niżMoveDuration, przerwij pętlę.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: breakRozważmy jeszcze ważny przypadek krańcowy: co się dzieje, gdy chcesz wykonać mniej niż pełny obrót? Dodajesz
TimePerRotationdoTotalTime, dlatego na początku pętliTotalTimemoże być dłuższy niżMoveDuration. W tej sytuacji musisz wykorzystać pozostały czas i, aby uwzględnić różnicę, wykonać mniej niż pełny obrót z krótszym czasem animacji. Aby uwzględnić taki przypadek, wykonaj poniższe kroki:Wróć do początku pętli i po aktualizacji
TotalTimeuruchom wyrażenieif. Wewnątrz tego wyrażenia zainicjuj zmiennąLeftoverTimei ustaw ją tak, aby była równa wynikowi odejmowaniaTotalTimeiMoveDuration, sprawdzając, czy wynik jest większy od0.0. To wyrażenie przypiszeLeftoverTimetylko wtedy, gdy porównanie będzie miało wartość true.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.0Aby dowiedzieć się, jaki ułamek obrotu musisz wykonać, zainicjuj nową zmienną
Frakcja obrotu, i ustaw ją równą różnicy międzyTimePerRotationaLeftoverTime, wszystko podzielone przezTimePerRotation.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)/TimePerRotationAby utworzyć zmodyfikowany obrót z
RotationFraction, użyjeszSlerp[]. To jest wersjaLerp(), która obsługuje interpolację sferyczną i ma podobne parametry. Znajduje najkrótszy obrót między dwoma różnymi obrotami i zwraca obrót na podstawie parametru interpolacji liniowej. WywołajSlerp[], interpolując międzyIdentityRotation()iIdentityRotation()obróconym oRotationToApply, używającRotationFractionjako parametru interpolacji liniowej. Używasz tutajIdentityRotation(), ponieważ interesuje cię tylko, jaki obrót ułamkowy masz zastosować, a nie w jakim obrocie końcowym ma byćEndTransform.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 interpolationPo skonfigurowaniu tych wartości ustaw
RotationToApplynaModifiedRotation, pomnóżAnimationTimeprzezRotationFraction, aby się dowiedzieć, o ile skrócić animację, na koniec ustawTotalTimenaMoveDuration, ponieważ nie chcesz, aby był dłuższy niż w przypadku obliczaniaEndTransform.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
Na samym końcu funkcji, po pętli, zwróć tablicę
Keyframes. Gotowa funkcjaBuildMovingAnimationKeyframes()powinna wyglądać następująco: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 thePo zdefiniowaniu logiki tworzenia klatek kluczowych czas utworzyć ich animację. Do utworzenia i wywołania animacji użyjesz osobnej funkcji. Dodaj nową funkcję
BuildAndPlayAnimation()do klasyanimating_prop. Do tej funkcji dodaj modyfikator<suspends>, aby mogła wywoływać inne asynchroniczne funkcje.Verse# Builds an animation from an array of keyframes, then calls MoveToEase() # to animate the prop. BuildAndPlayAnimation()<suspends>:void=W
BuildAndPlayAnimation()zainicjuj nową tablicękeyframe_deltao nazwieKeyframes. Następnie ustawKeyframesna wynik wywołaniaBuildMovingAnimationKeyframes(). Jako przekształcenie początkowe użyjRootProp.GetTransform(), ponieważ pozycja rekwizytu będzie się zmieniać między wywołaniamiMove(). Zainicjuj zmiennąanimation_modenaanimation_mode.OneShoti wywołajMoveToEase(), przekazując tablicęKeyframesiAnimationMode.Gotowa funkcja
BuildAndPlayAnimation()powinna wyglądać następująco: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.OneShotWróć do
Move()i wywołajBuildAndPlayAnimation()po ustawieniuTargetTransformna Przekształć cele ruchu.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()
Jest jeszcze jedna sprawa. Co się stanie, jeśli nie ustawisz żadnych celów ruchu? W takiej sytuacji rekwizyt powinien się dalej obracać w miejscu, nie przemieszczając się do nowej pozycji docelowej. Aby to obsłużyć, dodaj wyrażenie if na początku funkcji Move(). W if sprawdź, czy MoveTargets.Length = 0, jeśli tak jest, ustaw TargetTransform na przekształcenie rekwizytu głównego. Następnie wywołaj BuildAndPlayAnimation(). Dzięki temu rekwizyt będzie dalej animowany, nawet jeśli nie ustawisz celu ruchu. Ukończona animacja Move() powinna wyglądać następująco:
# 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()
Teraz musisz utworzyć odwołanie do animating_prop w swojej klasie prop_animator. W prop_animator dodaj edytowalną tablicę animating_prop o nazwie MoveAndRotateProps. W OnBegin(), w innym wyrażeniu for zainicjuj każdy rekwizyt w MoveAndRotateProps, wywołując Setup(). Gotowa klasa prop_animator powinna wyglądać następująco:
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.
Zapisz kod i go skompiluj.
Gratulacje, kod jest gotowy! Czas połączyć wszystko razem.
Utworzona klasa animating_prop może poruszać rekwizytami, obracać je i skalować. Wciąż jednak zależy ona od klasy moveable_prop, ponieważ musi dziedziczyć kilka funkcji, takich jak ManageMovement(). Biorąc pod uwagę, że klasa animating_prop może realizować wszystkie trzy typu ruchu, możesz uznać za przydatne refaktoryzację animating_prop, aby uwzględnić całą logikę moveable_prop, tak aby klasa mogła działać samodzielnie. Oto przykładowa refaktoryzacja, w której animating_prop i moveable_prop są połączone w jednym pliku. Zawiera również klasę urządzenia prop_animator verse. Co prawda wciąż potrzebujesz funkcjonalności z movement_behaviors, aby kod działał, ale dzięki tej refaktoryzacji wystarczą dwa pliki, a nie pięć. Ten kod znajduje się też w sekcji gotowego kodu.
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."
Łączenie rekwizytów z urządzeniami
Wróć do edytora, usuń sekcję toru po sekcji obracania rekwizytów, aby utworzyć lukę przed celem końcowym. Do poziomu dodaj kolejne FG01 SpinningBar Double S i FG01 Hover Platform M. Nadaj im nazwę SpinningMovingBar i TranslatingPlatform, a następnie dodaj kilka rekwizytów żarówki przycisku FG01, które będą elementami docelowymi, do których będzie przenoszony każdy rekwizyt. Nadaj im nazwę PlatformTarget. Umieść platformy i poprzeczkę nad luką, i pamiętaj, aby umieścić cele, do których platformy mają się przemieszczać. W tym przykładzie wirująca poprzeczka porusza się z boku na bok, a platforma porusza się do przodu i do tyłu.
Konfiguracja obracającego się paska i ruchomej platformy. Strzałki wskazują kierunki ruchu każdego rekwizytu. Poprzeczka i platforma poruszają się do przodu i do tyłu, przy czym w trakcie ruchu poprzeczka wiruje.
Wybierz swojego animatora rekwizytów w Outlinerze. Dodaj element tablicy do AnimatingProps dla obracającego się paska. Poszczególne wartości skonfiguruj w następujący sposób:
| Opcja | Wartość | Objaśnienie |
|---|---|---|
Dodatkowy obrót | 90.0 | Rekwizyt za każdym razem wykona obrót o 90 stopni. |
Szybkość obrotu | 1.5 | Rekwizyt będzie się obracał co |
Użyj łagodzenia na klatkę kluczową | false | Dla każdej klatki kluczowej będzie używany liniowy typ łagodzenia, aby poruszać rekwizytem i go obracać ze stałą szybkością. |
MoveTargets | 2 elementy przypisane do Celów platformy. | Są to cele, do których ma się poruszać pasek. |
RootProp | SpinningMovingBar | Jest to rekwizyt, który animujesz. |
Dla ruchomej platformy dodaj kolejny element tablicy do TranslatingProps. Przypisz MoveTargets do swojej platformy docelowej, a RootProp do TranslatingPlatform.
Naciśnij Uruchom sesję i spróbuj pokonać ukończony tor przeszkód!
Praca własna
Gotowe! Masz już wszystko, czego potrzebujesz, aby utworzyć własny tor przeszkód Fall Guys przy użyciu Verse!
Możesz użyć tego kodu, aby animować rekwizyty trybu kreatywnego w dowolnej swojej przygodzie, również w projektach innych niż Fall Guys!
Wykorzystując zdobytą wiedzę, spróbuj wykonać następujące czynności:
Twórz przeszkody, które obracają się w różnych kierunkach lub obracają się losowo na poziomie różnych klatek kluczowych.
Twórz przeszkody, które aktywują się tylko wtedy, gdy gracz na nich stanie lub podejdzie do nich na określoną odległość.
Opracuj platformy, które znikają po określonym czasie lub przenoszą gracza do niebezpiecznej pozycji, jeśli za długo stoi w miejscu.
Complete Code
Oto kompletny kod zbudowany w tej sekcji, łącznie z przykładową refaktoryzacją dla 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 (przykładowa refaktoryzacja 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."