Il y a plusieurs façons de déplacer des accessoires dans l'UEFN. Vous pouvez utiliser des fonctions comme TeleportTo[] ou MoveTo() pour modifier une transformation directement ou utiliser un autre appareil comme un déplaceur d'accessoire pour déplacer un accessoire sur un chemin prédéfini. Cependant, il existe une autre option utile sous la forme d'animations.
Chaque accessoire en mode Créatif possède un play_animation_controller que vous pouvez utiliser pour jouer son animation. Les animations présentent quelques avantages par rapport à la transformation de l'accessoire. Les animations permettent généralement d’obtenir des mouvements plus fluides que les objets déplacés avec MoveTo() ou TeleportTo(), car elles évitent la latence réseau liée à l'appel de ces fonctions à chaque tick de jeu. Les animations offrent également des collisions plus cohérentes avec les joueurs ou d’autres objets, et vous bénéficiez d’un meilleur contrôle sur le déplacement d’un objet (tant sur sa trajectoire que sur sa manière de se mouvoir) comparé à l'utilisation d'un déplaceur d’accessoire. Vous pouvez jouer des animations en boucle, ou les jouer dans les deux sens avec le mode ping-pong.
Les animations permettent également de choisir un type d'interpolation. Le type d'interpolation détermine le type d'assouplissement, ou courbe d'animation, que suit votre animation. Par exemple, le type d'interpolation linéaire joue votre animation à une vitesse constante, tandis que le type d'interpolation progressive commence lentement, puis accélère vers la fin. En choisissant le bon type d'interpolation pour votre animation, vous pouvez spécifier à différents moments si l'accessoire doit ralentir, accélérer ou se déplacer de manière linéaire.
En passant d'une animation à l'autre pour vos obstacles, vous pouvez créer une variété de défis différents pour les joueurs en utilisant les mêmes accessoires. Dans cette section, vous apprendrez à utiliser ce puissant outil pour créer vos propres animations et faire bouger vos accessoires !
Configurer les contrôles d'animation
Procédez comme suit pour configurer des contrôles d'animation pour vos accessoires :
À l'aide de l'explorateur Verse, créez un nouveau fichier Verse nommé
movement_behaviors. Celui-ci renfermera les fonctions utilitaires nécessaires à l'animation des accessoires.Ajoutez les instructions
using { /Fortnite.com/Devices },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.Dans le fichier
movement_behaviors, créez une nouvelleenumnomméemove_to_ease_type. Les valeurs de cette enum correspondent aux différents types d'assouplissement d'animation. Vous pouvez visualiser chacun de ces types d’assouplissement dans le moduleInterpolationTypes.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/Devices/CreativeAnimation } # Represents the different movement easing types. move_to_ease_type<public> := enum {Linear, Ease, EaseIn, EaseOut, EaseInOut}Ajoutez un nouvel
alias de typevector3 nomméVectorOnesqui crée unvector3oùX,YetZsont tous définis sur1,0. Vous utiliserez ce vecteur plus tard pour simplifier certains calculs, donc définir un alias de type permet d’éviter de répétervector3{X:=1.0, Y:=1.0, Z:=1.0}à chaque fois.Verse# Initializes a vector3 with all values set to 1.0. VectorOnes<public>:vector3 = vector3{X:=1.0, Y:=1.0, Z:=1.0}Ajoutez une nouvelle méthode
GetCubicBezierForEaseType()qui prend unmove_to_ease_typeet renvoie uncubic_bezier_parameters.Verse# Return the cubic_bezier_parameters based on the given move_to_ease_type. GetCubicBezierForEaseType(EaseType:move_to_ease_type):cubic_bezier_parameters=Le Bézier cubique se compose de quatre nombres qui définissent le type de fonction d'assouplissement utilisé par l'animation. Par exemple, les paramètres d'une courbe d'assouplissement ralentissent l'animation au début et l'accélèrent ensuite. Les paramètres d'une courbe linéaire permettent à l'animation de se dérouler à une vitesse constante. Vous pouvez définir ces valeurs vous-même pour créer vos propres courbes d’animation. Cela n’est cependant pas nécessaire dans cet exemple, car vous utiliserez celles définies dans le module
InterpolationTypes.Dans
GetCubicBezierForEaseType(), dans une expressioncase(), récupérez lescubic_bezier_parametersdu moduleInterpolationTypesen fonction dumove_to_ease_type. Par exemple,EaseOutdoit renvoyerInterpolationTypes.EaseOut,Lineardoit renvoyerInterpolationTypes.Linear, et ainsi de suite. Votre fonctionGetCubicBezierForEaseType()complète devrait ressembler à ceci :Verse# Return the cubic_bezier_parameters based on the given move_to_ease_type. GetCubicBezierForEaseType(EaseType:move_to_ease_type):cubic_bezier_parameters= case (EaseType): move_to_ease_type.Linear => InterpolationTypes.Linear move_to_ease_type.Ease => InterpolationTypes.Ease move_to_ease_type.EaseIn => InterpolationTypes.EaseIn move_to_ease_type.EaseOut => InterpolationTypes.EaseOut move_to_ease_type.EaseInOut => InterpolationTypes.EaseInOutRevenez à votre classe
movable_proppour ajouter un nouveaumove_to_ease_typemodifiable nomméMoveEaseType. Il s'agit du type d'assouplissement que votre accessoire appliquera à son animation.Verse# The type of animation easing to apply to the RootProp's movement. The easing type # changes the speed of the animation based on its animation curve. @editable {ToolTip := MoveEaseTypeTip} MoveEaseType:move_to_ease_type = move_to_ease_type.EaseInOut
Créer une animation avec des images clés
Pour créer des animations dans le code, vous utiliserez des images clés. Les animations sont constituées d'une ou plusieurs images clés, et chaque image clé spécifie les valeurs d'un objet à des moments précis de l'animation. En créant une animation à l'aide d'images clés, vous pouvez spécifier plusieurs points de déplacement, de rotation ou même de changement d'échelle pour votre accessoire.
Les images clés ont cinq valeurs. DeltaLocation, DeltaRotation et DeltaScale spécifient les modifications apportées à chaque valeur créée par l'accessoire du début à la fin de l'image clé. Il y a aussi Time, ou la durée en secondes de l'animation, et Interpolation, ou le mode d'interpolation de l'image clé. Une image clé peut ressembler à ceci :
# An example keyframe.
KeyFrame := keyframe_delta:
# The target position of the `creative_prop`. This is the difference between the starting and ending translation of the prop.
DeltaLocation := EndTransform.Translation - StartTransform.Translation,
# The target rotation for the `creative_prop` to rotate to.
DeltaRotation := EndTransform.Rotation,
# The target scale for the `creative_prop`. Scale is multiplicative to the starting Scale of the `creative_prop`
Procédez comme suit pour créer une animation à l'aide d'images clés :
Ajoutez une nouvelle méthode d'extension
creative_propnomméeMoveToEase()à votre fichiermovement_behaviors. Cette fonction prend en compte la position, la rotation et l'échelle de l'accessoire à déplacer, la durée de l'animation, le type d'assouplissement de mouvement et le mode d'animation.Verse# Animate a creative_prop by constructing an animation from a single keyframe, and then playing that animation on the prop. # This method takes a Position, Rotation, and Scale for the prop to end at, the duration of the animation, # the type of easing to apply to the movement, and the animation mode of the animation. (CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Rotation:rotation, Scale:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void=Dans
MoveToEase(), récupérez le contrôleur d'animation de l'accessoire en mode Créatif à l’aide deGetAnimationController[]. Le contrôleur d'animation vous permet de jouer des animations sur l'accessoire. Il expose également un événement qui déclenchera une attente plus tard.Verse(CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Rotation:rotation, Scale:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= # Get the animation controller for the CreativeProp to move. if (AnimController := CreativeProp.GetAnimationController[]):Calculez le changement d'échelle de l'accessoire, appelé
ScaleMultiplicative. Le paramètreScaleest un peu plus complexe dans cette situation. Étant donné que l'échelle est multiplicative, l'échelle de la transformation finale doit correspondre à la valeur de changement d'échelle de la transformation d'origine plutôt qu'à son échelle finale. Par exemple, si l'échelle de la transformation d'origine est de1,2et que vous souhaitez passer à une échelle de1,5, vous devez en réalité appliquer une échelle de1,25puisque1,2 * 1,25 = 1,5. La valeur finale estVectorOnesplus la différence entre la nouvelle et l'ancienne échelle divisée par l'ancienne échelle. Cette valeur est nécessaire pour s'assurer que l'animation se poursuit correctement en cas de modification de la taille au cours de l'animation.Verse# Calculate the multiplicative scale for the keyframe to scale to. ScaleMultiplicative:vector3 = VectorOnes + ((Scale - CreativeProp.GetTransform().Scale) / CreativeProp.GetTransform().Scale)Chaque animation a besoin d'une matrice d'images clés pour fonctionner. Dans cette fonction, vous n'utiliserez qu'une seule image clé et la convertirez en une matrice. Étant donné que cette matrice n'aura qu'une seule image clé, votre accessoire ne fera qu'un seul mouvement pour s'animer en douceur vers un nouvel emplacement. En outre, puisque vous appellerez
MoveToEase()à l'intérieur d'une boucle, l’accessoire peut continuer à s'animer sans qu'il soit nécessaire de spécifier plusieurs animations à la suite.Définissez une nouvelle matrice de
keyframe_deltanomméeKeyframes. Établissez une égalité entre cette matrice et une nouvelle matrice, puis créez un nouveaukeyfram_deltaà l'intérieur de cette nouvelle matrice.Verse# Build the keyframe array from a single keyframe_delta of the given values. Keyframes:[]keyframe_delta = array: keyframe_delta:Dans la définition de
keyframe_delta, initialisez chaque valeur nécessaire à la création de votre image clé. DéfinissezDeltaLocationsur la différence entre la nouvellePositionet la translation de l'accessoire en mode Créatif. Définissez laDeltaRotationsur laRotation, et laDeltaScalesur laScaleMultiplicativeque vous avez calculée plus tôt. Définissez l’argumentTimesurDuration, puis obtenez l’interpolationappropriée à définir en appelantGetCubicBezierForEaseType().Verse# Build the keyframe array from a single keyframe_delta of the given values. Keyframes:[]keyframe_delta = array: keyframe_delta: DeltaLocation := Position - CreativeProp.GetTransform().Translation, DeltaRotation := Rotation, DeltaScale := ScaleMultiplicative, Time := Duration, Interpolation := GetCubicBezierForEaseType(EaseType)Une fois votre matrice
Keyframescréée, définissez-la comme l'animation du contrôleur d'animation en utilisantSetAnimation()et en transmettant le modeAnimationMode. Jouez l'animation à l’aide de la fonctionPlay(), puis attendezMovementCompletedEventà l’aide de la fonctionAwait(). Votre méthode d’extensionMoveToEase()complète devrait ressembler à ceci :Verse# Animate a creative_prop by constructing an animation from a single keyframe, and then playing that animation on the prop. # This method takes a Position, Rotation, and Scale for the prop to end at, the duration of the animation, # the type of easing to apply to the movement, and the animation mode of the animation. (CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Rotation:rotation, Scale:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= # Get the animation controller for the CreativeProp to move. if (AnimController := CreativeProp.GetAnimationController[]): # Calculate the multiplicative scale for the keyframe to scale to. ScaleMultiplicative:vector3 = VectorOnes + ((Scale - CreativeProp.GetTransform().Scale) / CreativeProp.GetTransform().Scale)
Surcharge de fonctions
Bien que la fonction MoveToEase() que vous avez écrite soit utile, il peut être compliqué de lui transmettre un si grand nombre de variables à chaque appel. Il peut arriver que vous ne souhaitiez modifier qu'une partie de la transformation de l'accessoire, comme le déplacement ou la rotation. Il serait alors utile d'avoir une fonction plus simple à appeler dans ce cas.
Pour résoudre ce problème, vous pouvez tirer parti de la surcharge des fonctions. En surchargeant la fonction MoveToEase(), vous pouvez configurer plusieurs méthodes portant le même nom pour gérer différents types d'entrées. Procédez comme suit pour configurer vos fonctions surchargées.
Dans votre fichier
movement_behaviors, surchargez la fonctionMoveToEase()en créant une autre méthode d'extension de même nom, mais avec des entrées différentes. Cette fonctionMoveToEase()ne met à jour que la translation d'un accessoire, sans affecter la rotation et l’échelle. Cela signifie que vous n'avez besoin que des argumentsPosition,Duration,EaseTypeetAnimationMode.Verse# An overload of MoveToEase() that changes the position of the prop while keeping the rotation and scale the same. (CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void=Dans votre nouvelle fonction
MoveToEase(), appelez votre fonctionMoveToEase()d’origine, en transmettant toutes vos entrées plusIdentityRotation()etVectorOnescommeéchelle. La fonctionIdentityRotation()renvoie une rotation dont chaque valeur est fixée à0, donc(0,0,0). Il faut utiliserIdentityRotation()ici, car vous ne souhaitez pas ajouter de rotation à votre animation. Votre fonctionMoveToEase()surchargée devrait ressembler à ceci :Verse# An overload of MoveToEase() that changes the position of the prop while keeping the rotation and scale the same. (CreativeProp:creative_prop).MoveToEase<public>(Position:vector3, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= CreativeProp.MoveToEase(Position, IdentityRotation(), VectorOnes, Duration, EaseType, AnimationMode)Répétez ce processus pour créer une autre méthode surchargée qui ne modifie que la rotation, sans affecter la translation et l'échelle. Cette nouvelle méthode surchargée devrait ressembler à ceci :
Verse# An overload of MoveToEase() that changes the rotation of the prop while keeping the position and scale the same. (CreativeProp:creative_prop).MoveToEase<public>(Rotation:rotation, Duration:float, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= CreativeProp.MoveToEase(CreativeProp.GetTransform().Translation, Rotation, VectorOnes, Duration, EaseType, AnimationMode)Répétez l'opération pour créer une méthode qui ne modifie que l'échelle, tout en conservant la translation et la rotation. Cependant, étant donné que la
translationet l’échellesont toutes deux desvector3, la fonction résultante aurait la même signature que la surcharge que vous avez effectuée pour la translation, ce qui générerait une erreur. Vous pouvez résoudre ce problème en réorganisant les paramètres de la fonction. Inversez la position deDurationet deScalepour obtenir votre fonction surchargée. La méthode surchargée devrait ressembler à ceci :Verse# An overload of MoveToEase() that changes the position and scale of the prop while keeping the rotation the same. (CreativeProp:creative_prop).MoveToEase<public>(Duration:float, Scale:vector3, EaseType:move_to_ease_type, AnimationMode:animation_mode)<suspends>:void= CreativeProp.MoveToEase(CreativeProp.GetTransform().Translation, IdentityRotation(), Scale, Duration, EaseType, AnimationMode)Il est utile d'avoir une version de
MoveToEase()capable de prendre en charge plusieurs images clés. Vous pouvez gérer cela en configurant vos images clés à l'avance, et en les transmettant toutes àMoveToEase(). Ainsi, la fonction n'a qu'à configurer et jouer l'animation sur l'accessoire en mode Créatif. Ajoutez une nouvelle surcharge deMoveToEase()qui prend une matrice d'images clés et le mode d'animation en entrée.Verse# An overload of MoveToEase() that takes a pre-built array of keyframes and plays an animation. (CreativeProp:creative_prop).MoveToEase<public>(Keyframes:[]keyframe_delta, AnimationMode:animation_mode)<suspends>:void= if (AnimController := CreativeProp.GetAnimationController[]): AnimController.SetAnimation(Keyframes, ?Mode:=AnimationMode) AnimController.Play() AnimController.MovementCompleteEvent.Await()Enregistrez votre code et compilez-le.
Une fois vos méthodes configurées, il est temps de passer à l'action ! Dans la section suivante, vous déplacerez des accessoires pour créer des plateformes mobiles !
Code complet
Voici le code complet généré dans cette section :
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}