L'étape suivante, après les objets qui se déplacent, tournent ou changent d'échelle, consiste à leur faire faire les trois simultanément. Cependant, il y a des défis importants à relever lors de la création d'animations pour des accessoires qui se déplacent de plusieurs façons en même temps.
Étant donné que le contrôleur d'animation ne peut jouer qu'une seule animation à la fois, il n'est pas possible d'effectuer des déplacements, des rotations et des mises à l'échelle dans des animations distinctes. Ces animations nécessitent également plusieurs images clés, car il se peut que vous souhaitiez faire pivoter un accessoire plusieurs fois par animation. Étant donné que vous devez créer toutes les images clés à l'avance, vous devez également calculer la position, la rotation et l'échelle à chaque point du parcours de l'accessoire. Que se passe-t-il si votre accessoire n'effectue pas un nombre égal de rotations ? Comment gérer une demi-rotation ?
Cette section implique de nombreux calculs, mais à la fin, vous serez en mesure de déplacer, de faire pivoter et de changer l'échelle des accessoires en plusieurs points, et de créer des objets complexes, dynamiques et (le plus important !) des défis de plateforme amusants pour créer la course Fall Guys de vos rêves.
Créer des animations qui se déplacent, tournent et changent d'échelle
Procédez comme suit pour commencer à rassembler les éléments :
Créez une nouvelle classe Verse nommée
animating_propqui hérite demovable_propà l'aide de l'explorateur Verse. Ajoutez le spécificateur<concrete>à cette classe pour exposer ses propriétés à l'UEFN.Verse# A prop that translates, rotates, and scales to a destination using animation. animating_prop<public> := class<concrete>(movable_prop):Ajoutez les instructions
using { /Fortnite.com/Devices/CreativeAnimation }etusing { /UnrealEngine.com/Temporary/SpatialMath }en haut du fichier pour importer ces modules. Vous en aurez besoin pour animer votre accessoire. Les infobulles utilisées dans cette section sont également répertoriées ici.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):Ajoutez les champs suivants en haut de la définition de la classe
animating_prop:Une
rotationmodifiable nomméeAdditionalRotation. Il s'agit de la rotation à appliquer auRootProppar image clé.Verse# The additional rotation to apply to the RootProp per keyframe. @editable {ToolTip := AdditionalRotationTip} AdditionalRotation:rotation = rotation{}Un
floatmodifiable nomméRotationRate. Il s'agit du temps qu'il faut pour effectuer uneAdditionalRotation, en secondes.Verse# The time it takes to make one AdditionalRotation in seconds. @editable {ToolTip := RotationRateTip} var RotationRate:float = 1.0Une
logicmodifiable nomméeUseEasePerKeyFrame. Elle détermine si chaque image clé utilise leMoveEaseTypepour l'interpolation. Dans cet exemple, la valeurfalsepermet d'utiliser par défaut le type d'interpolation linéaire pour chaque image.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 = trueUne matrice modifiable de
creative_propnomméeMoveTargets. Il s'agit des différents accessoires en mode Créatif vers lesquels votre accessoire racine se déplacera.Verse# The Creative prop target for the RootProp to move toward. @editable {ToolTip := MoveTargetsTip} var MoveTargets:[]creative_prop = array{}Une variable
transformde variable nomméeTargetTransform. Il s'agit de la transformation vers laquelle votre accessoire racine se déplace actuellement.Verse# The transform the prop is currently targeting. var TargetTransform:transform = transform{}
La définition de votre classe devrait ressembler à ceci :
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):Remplacez la fonction
Move()dans votre classeanimating_prop. Ensuite, dans une expressionfor, itérez à chaqueMoveTargetde la matriceMoveTargets. Vérifiez si chaqueMoveTargetest valide, et si tel est le cas, définissez laTargetTransformsur la transformation de laMoveTarget.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.Dans votre fichier
movement_behaviors, ajoutez une nouvelle méthode nomméeBuildMovingAnimationKeyframes(). Cette fonction crée et renvoie une matrice d'images clés qui animent le déplacement et la rotation d'un accessoire en fonction d'une transformation cible. Cette fonction prend plusieurs paramètres d'animating_prop, notammentMoveDuration,RotationRate,AdditionalRotation,OriginalTransform(la transformation de départ de l'accessoire),TargetTransform,MoveEaseTypeet une nouvelle valeurlogicappeléeUseEasePerKeyframe. Cela détermine si l'on utilise leMoveEaseTypepour chaque image clé. La signature de votre fonction doit ressembler à ceci :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=Dans
BuildMovingAnimationKeyframes(), initialisez les variables suivantes :Une matrice variable de
keyframe_deltanomméeKeyframes. Il s'agit de la matrice que vous renverrez à la fin.Verse# The array of keyframes to return. var KeyFrames:[]keyframe_delta = array{}Une variable
floatnomméeTotalTime. Il s'agit du temps total consacré à l'animation jusqu'à présent.Verse# The total amount of time spent animating. var TotalTime:float = 0.0Deux variables
transformnomméesStartTransformetEndTransform. Il s'agit des transformations de départ et de fin de l'accessoire au début et à la fin de chaque image clé. Initialisez les deux à l'OriginalTransform.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 = OriginalTransformUne variable
rotationnomméeRotationToApply, initialisée à l'AdditionalRotation. Il s'agit de la rotation réelle que vous appliquerez à l'accessoire pour chaque image clé. En général, il s'agit de l'AdditionalRotation, mais si vous avez besoin d'effectuer une rotation fractionnaire, vous devez changer cette valeur.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 = AdditionalRotationUne variable
floatnomméeAnimationTime. Il s'agit de la durée en secondes de chaque image clé. Initialisez cette valeur sur1.0 / RotationRate, puisque le RootProp doit effectuer un nombre deRotationRaterotations par seconde.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 / RotationRateUne valeur
floatnomméeTotalRotations. Il s'agit du nombre total de rotations à effectuer sur l'ensemble de l'animation, et il est initialisé àMoveDuration * RotationRate. La raison pour laquelle il s'agit d'unfloatet non d'unintest que cela permet de gérer les situations où il n'est pas nécessaire d'effectuer une rotation complète, comme à la fin d'une animation.Verse# The total number of rotations to make. TotalRotations:float = MoveDuration * RotationRateUne valeur
floatnomméeTimePerRotation. Il s'agit du temps en secondes nécessaire pour effectuer une rotation. Votre fonction devrait maintenant ressembler à ceci.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
Cela représente un grand nombre de valeurs à prendre en compte. Faisons donc un exemple de calcul, en utilisant 2.5 comme RotationRate et 5.0 comme 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 =
Avec un RotationRate de 2,5 et une MoveDuration de 5,0, vous effectuerez 12,5 rotations au total, chaque rotation prenant 0,4 seconde. Cela signifie que vous devrez effectuer une demi-rotation supplémentaire à la fin de l'animation. Vous remarquerez également que la durée de l'animation et le temps par rotation sont identiques. C'est presque toujours le cas, sauf lorsque l'on doit effectuer moins d'une rotation complète. Même si elles ont initialement la même valeur, vous devrez garder une trace des deux variables pour effectuer des calculs ultérieurs.
Créer des images clés dans une boucle
Il est temps de passer à l'action ! Procédez comme suit pour configurer la boucle de création de vos images clés.
Ajoutez une expression
loopàBuildMovingAnimationKeyframes(). À chaque itération de la boucle, vous créerez une nouvelle image clé et l'ajouterez à la matrice des images clés. Au début de la boucle, mettez à jour laTotalTimeavec leTimePerRotation.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 += TimePerRotationCréez l'
EndTransform, qui est l'endroit où l'accessoire doit se trouver à la fin de cette image clé. Définissez l'EndTransformsur une nouvelle transformation avec les paramètres suivants :Définissez la
Translationsur le résultat de l'appel deLerp()entre l'OriginalTransformet laTargetTransform. La fonctionLerp()prend deux valeurs et un rapport de Lerp compris entre0,0et1,0. Elle génère ensuite une nouvelle valeur située entre les deux, sur la base du rapport de Lerp. Plus le rapport de Lerp est proche de 1.0, plus la transformation sera proche deTargetTransform, et inversement.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))Définissez la
Rotationsur le résultat deMakeShortestRotationBetween(), en transmettant la rotation de la transformation d'origine et la transformation d'origine pivotée deRotationToApply.VerseTranslation := Lerp(OriginalTransform.Translation, TargetTransform.Translation, (TotalTime * RotationRate) / (TotalRotations)) Rotation := MakeShortestRotationBetween(OriginalTransform.Rotation, OriginalTransform.Rotation.RotateBy(RotationToApply))~~~Définissez l'
échellesur le résultat de l'appel deLerp()entre l'OriginalTransform.Scaleet laTargetTransform.Scale. Gardez à l'esprit qu'il s'agit de l'échelle à appliquer à l'accessoire, et non de la valeur de changement d'échelle. VotreEndTransformcomplète doit ressembler à ceci :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)
Une fois la transformation finale définie, il est temps de créer une image clé ! Il s'agit en grande partie du même processus que vous avez suivi pour votre fonction
MoveToEase(). Créez une nouvelle variablekeyframe_deltanomméeKeyFrame. Définissez la valeur deDeltaLocationsur la différence entre les déplacements de transformation de fin et de début. Définissez laDeltaRotationsur la rotation de la transformation finale. Puisque vous devez calculer le changement d'échelle, définissez laDeltaScalesur le résultat de la division de l'échelle de la transformation de fin par celle de la transformation de départ. La duréeTimedoit être la durée d'AnimationTime, etInterpolationTypedoit être le résultat d'une expressionif. SiUseEasePerKeyframeest activé, utilisez leMoveEaseType. Dans le cas contraire, utiliser le type linéaire. Votre expression d'image clé devrait ressembler à ceci :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:Une fois votre image clé créée, vous pouvez maintenant l'ajouter à la matrice
Keyframes. Définissez ensuite laStartTransformsur l'EndTransformafin de la mettre à jour pour l'image clé suivante. Enfin, si laTotalTimeest maintenant supérieure à laMoveDuration, la boucle s'arrête.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: breakIl existe un cas dont il faut tenir compte : que se passe-t-il lorsque l'on a besoin d'effectuer moins d'une rotation complète ? Étant donné qu'on ajoute le
TimePerRotationà laTotalTime, cela signifie que laTotalTimepourrait être plus élevée que laMoveDurationau début de la boucle. Dans cette situation, vous devez gérer le temps restant et effectuer une rotation inférieure à la rotation complète, avec un temps d'animation plus court pour tenir compte de la différence. Procédez comme suit pour tenir compte de cette situation :Au début de la boucle, après avoir mis à jour
TotalTime, lancez une expressionif. À l'intérieur, initialisez une variableLeftoverTimeet rendez-la égale au résultat de la soustraction deTotalTimeetMoveDuration, en vérifiant si elle est supérieure à0,0. Cette expression n'attribueraLeftoverTimeque si la comparaison est activée.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.0Pour savoir quelle fraction de rotation vous devez effectuer, initialisez une nouvelle variable
Rotation Fraction, et définissez-la sur la différence entre leTimePerRotationet leLeftoverTime, le tout divisé par leTimePerRotation.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)/TimePerRotationPour créer une rotation modifiée à partir de la
RotationFraction, vous utiliserezSlerp[]. Il s'agit de la version deLerp()qui gère l'interpolation sphérique et qui a des paramètres similaires. Elle recherche la rotation la plus courte entre deux rotations différentes et renvoie une rotation en fonction du paramètre du lerp. AppelezSlerp[], en interpolant entre l'IdentityRotation()et l'IdentityRotation()pivoté en fonction deRotationToApply, en utilisant laRotationFractioncomme paramètre de lerp. Nous utilisonsIdentityRotation()ici parce que seule la rotation fractionnaire que nous devons appliquer nous intéresse, et non pas la rotation finale de l'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 interpolationUne fois ces valeurs définies, définissez la
RotationToApplysur laModifiedRotation, multipliez l'AnimationTimepar laRotationFractionpour savoir de combien raccourcir votre animation, et définissez enfin laTotalTimesur laMoveDurationpuisqu'elle n'est pas censée la dépasser lors du calcul de l'EndTransform.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
À la toute fin de votre fonction, après la boucle, renvoyez la matrice
Keyframes. Votre fonctionBuildMovingAnimationKeyframes()complète devrait ressembler à ceci :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 theMaintenant que vous avez défini la logique de création de vos images clés, il est temps de les animer. Vous utiliserez une fonction distincte pour créer et appeler votre animation. Ajoutez une nouvelle fonction
BuildAndPlayAnimation()à votre classeanimating_prop. Ajoutez le modificateur<suspends>à cette fonction pour lui permettre d'appeler d'autres fonctions asynchrones.Verse# Builds an animation from an array of keyframes, then calls MoveToEase() # to animate the prop. BuildAndPlayAnimation()<suspends>:void=Dans
BuildAndPlayAnimation(), initialisez une nouvelle matricekeyframe_deltanomméeKeyframes. Ensuite, définissezKeyframessur le résultat de l'appel deBuildMovingAnimationKeyframes(). UtilisezRootProp.GetTransform()comme transformation de départ puisque la position de l'accessoire changera entre les appels deMove(). Initialisez une variableanimation_modesuranimation_mode.OneShotet appelezMoveToEase()en transmettant la matriceKeyframeset l'AnimationMode.Votre fonction
BuildAndPlayAnimation()complète devrait ressembler à ceci :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.OneShotDe retour dans
Move(), appelezBuildAndPlayAnimation()après avoir défini laTargetTransformsur la transformation des cibles du déplacement.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()
Il existe un autre cas à prendre en considération. Que se passe-t-il si l'on ne définit pas de cibles de déplacement ? Dans ce cas, l'accessoire doit continuer à tourner sur place, sans changer de destination. Pour gérer cela, ajoutez une expression if au début de votre fonction Move(). Dans l'expression if, vérifiez si MoveTargets.Length = 0, et si tel est le cas, définissez la TargetTransform sur la transformation de l'accessoire racine. Ensuite, appelez BuildAndPlayAnimation(). De cette façon, votre accessoire continuera à s'animer même si vous n'avez pas défini de cible de déplacement. Votre animation Move() complète devrait ressembler à ceci :
# 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()
Vous devez maintenant référencer animating_prop dans votre classe prop_animator. Dans prop_animator, ajoutez une matrice modifiable d'animating_prop nommée MoveAndRotateProps. Dans une autre expression for dans OnBegin(), initialisez chaque accessoire de MoveAndRotateProps en appelant Setup(). Votre classe prop_animator complète devrait ressembler à ceci :
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.
Enregistrez votre code et compilez-le.
Félicitations, le code est maintenant terminé ! Il est maintenant temps de tout relier.
La classe animating_prop que vous venez de créer peut déplacer les accessoires, les faire pivoter et changer leur échelle. Cependant, elle reste dépendante de la classe moveable_prop, car elle doit hériter de plusieurs fonctions telles que ManageMovement(). Étant donné que la classe animating_prop peut effectuer les trois types de mouvement, vous pourriez trouver utile de refactoriser animating_prop pour inclure toute la logique de moveable_prop de façon à ce que la classe puisse être autonome. Un exemple de refactorisation fusionnant animating_prop et moveable_prop en un seul fichier est inclus ici. Il inclut également la classe d'appareil Verse prop_animator. Vous aurez toujours besoin de la fonctionnalité de movement_behaviors pour que votre code fonctionne, mais cette refactorisation réduit le nombre de fichiers nécessaires de cinq à deux. Ce code est également inclus dans la section Code complet.
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."
Lier des accessoires aux appareils
De retour dans l'éditeur, supprimez une section de la course après la section des accessoires rotatifs afin de créer un espace vide avant l'objectif final. Ajoutez une autre FG01 Barre rotative double S et une FG01 Plaque de lévitation M à votre niveau. Nommez-les SpinningMovingBar et TranslatingPlatform, puis ajoutez plusieurs accessoires FG01 Bouton ampoule, qui seront les cibles vers lesquelles chaque accessoire se déplacera. Nommez-les PlatformTarget. Placez les plateformes et la barre au-dessus de l'espace vide, et assurez-vous de placer les cibles là où vous voulez que les plateformes se déplacent. Dans cet exemple, la barre tournante se déplace d'un côté à l'autre, tandis que la plateforme se déplace d'avant en arrière.
Configurer la barre tournante et la plateforme mobile. Les flèches indiquent la direction dans laquelle chaque accessoire se déplace. La barre tournante et la plateforme se déplacent d'avant en arrière, et la barre tournante tourne en même temps qu'elle se déplace.
Sélectionnez votre animateur d'accessoire dans l'organiseur. Ajoutez un élément de matrice à AnimatingProps pour votre barre tournante. Définissez chaque valeur comme suit :
| Option | Value | Explication |
|---|---|---|
Rotation supplémentaire | 90,0 | Cet accessoire effectuera une rotation de 90 degrés à chaque fois. |
Vitesse de rotation | 1,5 | Cet accessoire effectuera une rotation toutes les |
Utiliser l'accélération/la décélération par image clé | false | Cette option utilise le type d'accélération linéaire sur chaque image clé pour déplacer et faire pivoter l'accessoire à vitesse constante. |
MoveTargets | 2 éléments, assignés aux cibles de plateforme. | Il s'agit des cibles vers lesquelles vous souhaitez que la barre se déplace. |
RootProp | SpinningMovingBar | Il s'agit de l'accessoire que vous animez. |
Ajoutez un autre élément de matrice à TranslatingProps pour votre plateforme mobile. Assignez les MoveTargets aux cibles de votre plateforme, et le RootProp à votre TranslatingPlatform.
Appuyez sur Lancer la session et essayez de traverser votre course d'obstacles jusqu'au bout !
À vous de jouer
Vous avez terminé ! Vous avez maintenant en main tous les outils nécessaires pour créer votre propre course d'obstacles Fall Guys à l'aide de Verse !
Vous pouvez utiliser le code indiqué ici pour animer des accessoires en mode Créatif dans n'importe laquelle de vos expériences, et même au-delà des projets Fall Guys !
Utilisez vos connaissances pour vous essayer aux défis suivants :
Créez des obstacles qui tournent dans différentes directions ou qui tournent de manière aléatoire entre les images clés.
Créez des obstacles qui ne s'activent que lorsqu'un joueur se trouve au-dessus ou à une certaine distance.
Trouvez comment créer des plateformes qui disparaissent au bout d'un certain temps ou déplacez le joueur à des endroits dangereux s'il reste trop longtemps sur une plateforme.
Code complet
Voici le code complet créé dans cette section, y compris un exemple de refactorisation d'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):
rotation_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 (exemple de refactorisation d'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."