Hay varias maneras en las que se pueden mover utilerías en UEFN. Puedes usar funciones como TeleportTo[] o MoveTo() para modificar una transformación directamente, o usar otro dispositivo como un movedor de utilería para mover una utilería en una trayectoria preestablecida. Sin embargo, hay otra opción útil a través de las animaciones.
Cada utilería del modo Creativo tiene un play_animation_controller que puedes usar para reproducir animaciones de esta. Las animaciones tienen un par de beneficios con respecto a mover la transformación de la utilería. Las animaciones suelen tener un movimiento más suave que los objetos en movimiento con MoveTo() o TeleportTo() porque evitan la latencia de red de tener que llamar a estas funciones en cada tic del juego. Las animaciones también tienen colisiones más consistentes con los jugadores u otros objetos, y tienes un mayor nivel de control sobre dónde y cómo se mueve un objeto respecto a usar un dispositivo movedor de utilería. Puedes reproducir animaciones en bucle o reproducirlas hacia adelante o hacia atrás con el modo ping-pong.
Las animaciones también te dejan escoger un tipo de interpolación. El tipo de interpolación determina el tipo de suavizado, o la curva de animación, que tu animación sigue. Por ejemplo, el tipo de interpolación lineal reproduce tu animación a una velocidad constante, mientras que el tipo de entrada suave comienza despacio y luego acelera hacia el final. Al escoger el tipo de interpolación correcto para tu animación, puedes especificar en diferentes puntos si la utilería debería ralentizarse, acelerarse o moverse linealmente.
Al cambiar entre diferentes animaciones para tus obstáculos, puedes crear una variedad de distintos desafíos para los jugadores usando las mismas utilerías. En esta sección, aprenderás a usar esta poderosa herramienta para crear tus propias animaciones y hacer que tus utilerías se muevan.
Cómo configurar los controles de animación
Sigue estos pasos para configurar los controles de animación para tus utilerías:
Usando el explorador de Verse, crea un nuevo archivo de Verse llamado
movement_behaviors. Allí se almacenarán las funciones de utilidad que necesitas para animar las utilerías.Añade las instrucciones
que usen { /Fortnite.com/Devices },que usen { /Fortnite.com/Devices/CreativeAnimation }yque usen { /UnrealEngine.com/Temporary/SpatialMath }en la parte superior del archivo para importar estos módulos. Los necesitarás para animar tu utilería.En
movement_behaviors, crea un nuevoenumllamadomove_to_ease_type. Los valores en este enum corresponden a los distintos tipos de suavizado de animación. Puedes ver cada uno de estos tipos de suavizado en el móduloInterpolationTypes.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}Añade un nuevo alias de tipo
vector3llamadoVectorOnesque haga unvector3dondeX,Y, yZestén establecidos en1.0. Usarás este vector luego para hacer cálculos matemáticos con más facilidad, de modo que definir un alias de tipo significa que no tienes que escribirvector3{X:=1.0, Y:=1.0, Z:=1.0}reiteradas veces.Verse# Initializes a vector3 with all values set to 1.0. VectorOnes<public>:vector3 = vector3{X:=1.0, Y:=1.0, Z:=1.0}Añade un nuevo método
GetCubicBezierForEaseType()que recibe unmove_to_ease_typey devuelve 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=El bézier cúbico consta de cuatro números que definen el tipo de función de suavizado que la animación usa. Por ejemplo, los parámetros para una curva de entrada suave hacen que la animación se ralentice al inicio y se acelere después. Los parámetros para una curva lineal hacen que la animación se reproduzca a una velocidad constante. Puedes definir estos valores tú mismo para crear tus propias curvas de animación personalizadas, pero no necesitas hacerlo en este ejemplo, ya que usarás las que están definidas en el módulo
InterpolationTypes.En
GetCubicBezierForEaseType(), en una expresióncase(), obtén loscubic_bezier_parametersen el móduloInterpolationTypescon base en elmove_to_ease_type. Por ejemplo,EaseOutdebería devolverInterpolationTypes.EaseOut,Lineardebería devolverInterpolationTypes.Linear, y así sucesivamente. Tu funciónGetCubicBezierForEaseType()completa debería verse de la siguiente manera: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.EaseInOutDe vuelta en tu clase
movable_prop, añade un nuevomove_to_ease_typeeditable llamadoMoveEaseType. Este es el tipo de suavizado que tu utilería aplicará a su animación.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
Cómo crear una animación con fotogramas clave
Para compilar animaciones en código, vas a utilizar fotogramas clave. Las animaciones están compuestas por uno o más fotogramas clave, y cada fotograma clave especifica los valores de un objeto en puntos específicos de la animación. Al crear una animación usando fotogramas clave, puedes especificar múltiples puntos a los que se puede mover, rotar o incluso escalar tu utilería.
Los fotogramas clave tienen cinco valores. En DeltaLocation, DeltaRotation y DeltaScale se especifican los cambios en cada valor que realiza la utilería desde el inicio hasta el final del fotograma clave. También está Time, o la cantidad de tiempo en segundos que dura la animación, e Interpolation, o el modo de interpolación para el fotograma clave. Un fotograma clave de ejemplo podría verse así:
# 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`
Sigue estos pasos para crear una animación usando fotogramas clave:
Añade un nuevo método de extensión
creative_propllamadoMoveToEase()a tu archivomovement_behaviors. Esta función recibe una posición, una rotación y una escala para que la utilería se mueva; una duración para la animación; un tipo de suavizado de movimiento, y un modo de animación.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=En
MoveToEase(), obtén el controlador de animación de la utilería del modo Creativo y utilizaGetAnimationController[]. El controlador de animación es lo que te permite reproducir las animaciones sobre la utilería, y también expone un evento que esperarás luego.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[]):Calcula el cambio en escala de la utilería, llamado
ScaleMultiplicative. LaScalees un poco más compleja en esta situación. Dado que la escala es multiplicativa, la escala de la transformación final debe ser la cantidad por la que debe escalarse la transformación original, en lugar de la cantidad a la que debe escalarse. Por ejemplo, si la escala de la transformación original es1.2y querías escalar a1.5, en realidad necesitas escalar en1.25, ya que1.2 * 1.25 = 1.5. El valor final esVectorOnesmás la diferencia entre la escala nueva y la escala vieja dividida por la escala vieja. Necesitas este valor para garantizar que tu animación se siga animando adecuadamente si cambias su tamaño durante la animación.Verse# Calculate the multiplicative scale for the keyframe to scale to. ScaleMultiplicative:vector3 = VectorOnes + ((Scale - CreativeProp.GetTransform().Scale) / CreativeProp.GetTransform().Scale)Cada animación necesita una matriz de fotogramas clave para ejecutarse. En esta función, solo usarás un fotograma clave y convertirás su tipo en una matriz. Dado que esta matriz solo tendrá un fotograma clave, tu utilería hará un movimiento para animarla suavemente hacia una nueva ubicación. Y dado que llamarás a
MoveToEase()dentro de un bucle, la utilería se puede seguir animando sin tener que especificar varias animaciones consecutivas.Define una nueva matriz de
keyframe_deltallamadaKeyframes. Define esta matriz igual a una nueva matriz, y dentro de esa matriz crea un nuevokeyfram_delta.Verse# Build the keyframe array from a single keyframe_delta of the given values. Keyframes:[]keyframe_delta = array: keyframe_delta:Dentro de la definición de
keyframe_delta, inicializa cada valor necesario para compilar tu fotograma clave. Establece laDeltaLocationen la diferencia entre la nuevaPositiony la traslación de la utilería del modo Creativo. EstableceDeltaRotationenRotationyDeltaScaleenScaleMultiplicativeque calculaste anteriormente. EstableceTimeenDurationy obtén laInterpolationcorrecta para establecerla llamando aGetCubicBezierForEaseType().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)Una vez que creaste la matriz de
Keyframes, establécela como la animación del controlador de animación medianteSetAnimation(), pasando elAnimationMode. Reproduce la animación conPlay(), luego utilizaAwait()para esperar elMovementCompletedEvent. Tu método de extensiónMoveToEase()completo debería verse de la siguiente manera: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)
Sobrecarga de funciones
Aunque la función MoveToEase() que escribiste es útil, puede ser complicado pasarle tantas variables a la función cada vez que la llamas. Puede haber situaciones en las que solo quieres cambiar una parte de la transformación de la utilería, como la traslación o la rotación, y sería útil tener una función más simple para llamar en este caso.
Para solucionar esto, puedes aprovechar la sobrecarga de funciones. Al sobrecargar la función MoveToEase(), puedes establecer varios métodos con el mismo nombre para manejar diferentes tipos de entradas. Sigue estos pasos para crear funciones sobrecargadas.
En tu archivo
movement_behaviors, sobrecarga la funciónMoveToEase()mediante la creación de otro método de extensión con el mismo nombre pero diferentes entradas. EsteMoveToEase()solo actualizará la traslación de una utilería sin modificar la rotación ni la escala. Esto significa que solo necesitas los argumentosPosition,Duration,EaseTypeyAnimationMode.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=En tu nueva función
MoveToEase(), llama a la funciónMoveToEase()original y pásale todas las entradas más laIdentityRotation()yVectorOnescomo laScale. LaIdentityRotation()devuelve una rotación con cada valor en0, es decir,(0,0,0). Necesitas laIdentityRotation()aquí porque no quieres añadirle una rotación a tu animación. Tu función sobrecargadaMoveToEase()debería verse de la siguiente manera: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)Repite este proceso a fin de crear otro método sobrecargado que solo cambie la rotación y conserve la traslación y la escala. Este nuevo método sobrecargado debería verse así:
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)Repítelo para crear un método que solo cambie la escala y mantenga la traslación y la rotación. Sin embargo, dado que tanto
translationcomoscalesonvector3, la función resultante tendría la misma firma que la función sobrecargada que creaste para la traslación, lo cual producirá un error. Puedes resolver esto cambiando el orden de los parámetros de la función. Intercambia la posición deDurationyScalepara crear tu función sobrecargada. El método sobrecargado debería verse así: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)Es útil tener una versión de
MoveToEase()que pueda controlar varios fotogramas clave. Puedes controlarlo mediante la configuración de tus fotogramas clave de antemano y pasándoselos todos aMoveToEase(). De esa manera, la función solo necesita establecer y reproducir la animación en la utilería del modo Creativo. Añade una nueva sobrecarga deMoveToEase()que reciba una matriz de fotogramas clave y el modo de animación como entradas.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()Guarda tu código y compílalo.
Ya con tus métodos listos, es hora de de ponerse en marcha. En la próxima sección, trasladarás las utilerías para crear plataformas móviles.
Código completo
Esa es la versión completa del código en esta sección:
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}