Existen varias maneras de mover elementos en UEFN. Puedes utilizar funciones como TeleportTo[] o MoveTo() para modificar directamente una transformación, o utilizar otro dispositivo como un colocador de elementos para mover un elemento en una ruta preestablecida. No obstante, existe otra opción útil en forma de animaciones.
Cada elemento del modo Creativo tiene un play_animation_controller que puedes utilizar para reproducir animaciones del mismo. Las animaciones presentan un par de ventajas sobre el movimiento de transformación del elemento. Las animaciones normalmente tienen un movimiento más suave que mover objetos con MoveTo() o TeleportTo(), ya que evitan la latencia de red que supone tener que llamar a estas funciones cada tic de juego. Las animaciones también tienen colisiones más uniformes con los jugadores u otros objetos, y tienes un mayor nivel de control sobre dónde y cómo se mueve un objeto en comparación con el uso de un dispositivo Colocador de elementos. Puedes reproducir animaciones en bucle o reproducirlas hacia delante y hacia atrás con el modo ping-pong.
Las animaciones también te permiten elegir un tipo de interpolación. El tipo de interpolación determina el tipo de aceleración, o curva de animación, que seguirá la animación. Por ejemplo, el tipo de interpolación lineal reproduce la animación a una velocidad constante, mientras que el tipo de entrada lenta empieza despacio y luego se acelera hacia el final. Al elegir el tipo de interpolación adecuado para tu animación, puedes especificar en diferentes puntos si el elemento debe ralentizarse, acelerarse o moverse linealmente.
Al cambiar entre diferentes animaciones para tus obstáculos, puedes crear una variedad de desafíos diferentes para los jugadores utilizando los mismos elementos. En esta sección aprenderás a utilizar esta potente herramienta para crear tus propias animaciones y conseguir que tus elementos se muevan.
Cómo configurar los controles de animación
Sigue los pasos que se indican a continuación para configurar los controles de animación de tus elementos:
Con el explorador de Verse, crea un nuevo archivo de Verse con el nombre
movement_behaviors. Aquí se almacenarán las funciones de utilidad que necesitas para animar los elementos.Añade las declaraciones
using { /Fortnite.com/Devices },using { /Fortnite.com/Devices/CreativeAnimation }yusing { /UnrealEngine.com/Temporary/SpatialMath }en la parte superior del archivo para importar estos módulos. Necesitarás estos módulos para animar el elemento.En
movement_behaviors, crea un nuevoenumcon el nombremove_to_ease_type. Los valores de este enumerador corresponden a los diferentes tipos de aceleración de animación. Puedes ver cada uno de estos tipos de aceleración en el móduloTipos de interpolación.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 tipovector3 con el nombreVectorOnesque cree unvector3dondeX,YyZestén configurados como1.0. Más adelante utilizarás este vector para simplificar algunas operaciones matemáticas, por lo que definir un alias de tipo para él significa que no tienes que escribirvector3{X:=1.0, Y:=1.0, Z:=1.0}repetidamente.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 reciba unmove_to_ease_typey deuvelva 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 cúbico de Bézier consta de cuatro números que definen el tipo de función de aceleración que utiliza la animación. Por ejemplo, los parámetros para una curva de entrada lenta hacen que la animación sea más lenta al principio 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 por tu cuenta estos valores para crear tus propias curvas de animación personalizadas, pero en este ejemplo no será necesario dado que utilizarás las definidas en el módulo
InterpolationTypes.En
GetCubicBezierForEaseType(), en una expresióncase(), obtén loscubic_bezier_parametersdel móduloInterpolationTypesen función delmove_to_ease_type. Por ejemplo,EaseOutdebería devolverInterpolationTypes.EaseOut,Lineardebería devolverInterpolationTypes.Linear, y así sucesivamente. Tu función completaGetCubicBezierForEaseType()debería tener este aspecto: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.EaseInOutEn tu clase
movable_prop, añade un nuevomove_to_ease_typeeditable con el nombreMoveEaseType. Este es el tipo de aceleración que tu elemento 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 construir una animación con fotogramas clave
Para construir animaciones en código, vas a utilizar fotogramas clave. Las animaciones se crean a partir de uno o varios fotogramas clave, y cada fotograma clave especifica los valores de un objeto en determinados puntos de la animación. Al construir una animación mediante fotogramas clave, puedes especificar múltiples puntos para que el elemento se mueva, gire o incluso se escale.
Los fotogramas clave tienen cinco valores. Los valores DeltaLocation, DeltaRotation y DeltaScale especifican los cambios en cada valor que realiza el elemento desde el inicio hasta el final del fotograma clave. También existe el valor Time, o la cantidad de tiempo en segundos que dura la animación, y el valor Interpolation, o el modo de interpolación para el fotograma clave. Un ejemplo de fotograma clave podría tener este aspecto:
# 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 construir una animación utilizando fotogramas clave:
Añade un nuevo método de extensión
creative_propcon el nombreMoveToEase()a tu archivomovement_behaviors. Esta función recibe la posición, rotación y escala del elemento a las que se va a mover, una duración de la animación, un tipo 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 del elemento del modo Creativo utilizandoGetAnimationController[]. El controlador de animación te permite reproducir animaciones en el elemento y también expone un evento que esperarás más adelante.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 de escala del elemento, nombrado
ScaleMultiplicative.Scalees un poco más complejo en esta situación. Puesto que la escala es multiplicativa, es necesario que la escala de la transformación final sea la cantidad a la que debe escalar la transformación original, en vez de la cantidad a la que debe escalar. Por ejemplo, si la escala de la transformación original es1.2y quieres escalar a1.5, en realidad tendrás que escalar a1.25, ya que1.2 * 1.25 = 1.5. El valor final esVectorOnesmás la diferencia entre la nueva escala y la anterior dividido por la escala anterior. Necesitas este valor para asegurarte de que tu animación sigue animándose correctamente en caso de que cambies 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 su ejecución. En esta función, utilizarás un único fotograma clave y lo transmitirás a una matriz. Como esta matriz solo tendrá un fotograma clave, tu elemento hará un solo movimiento para animarse suavemente en una nueva ubicación. Y dado que estarás llamando a
MoveToEase()dentro de un bucle, el elemento puede seguir animándose sin tener que especificar múltiples animaciones seguidas.Define una nueva matriz de
keyframe_deltacon el nombreKeyframes. Establece 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
keyframe_delta, inicializa cada valor necesario para construir tu fotograma clave. Establece el valorDeltaLocationcomo la diferencia entre la nuevaPositiony la traslación del elemento del modo Creativo. EstableceDeltaRotationcomoRotation, yDeltaScalecomoScaleMultiplicativeque calculaste anteriormente. EstableceTimecomoDurationy obtén el valor deInterpolationadecuado para establecer 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)Con la matriz de
Keyframescreada, establécela como la animación del controlador de animación medianteSetAnimation(), pasando elAnimationMode. Reproduce la animación conPlay(), después utilizaAwait()paraMovementCompletedEvent. Tu método de extensiónMoveToEase()completo debería tener el siguiente aspecto: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)
Cómo sobrecargar funciones
Si bien la función MoveToEase() que escribiste resulta útil, podría ser complicado pasar un número tan grande de variables a la función cada vez que quieras llamarla. Es posible que haya situaciones en las que solo quieras cambiar una parte de la transformación del elemento, como la traslación o la rotación, y sería útil disponer de una función más sencilla a la que llamar en este caso.
Para solucionar esto, puedes aprovechar la sobrecarga de funciones. Al sobrecargar la función MoveToEase(), puedes configurar varios métodos con el mismo nombre para gestionar diferentes tipos de entradas. Sigue los pasos que se indican a continuación para configurar tus 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 un elemento, dejando la rotación y la escala sin cambios. Esto implica que solo necesitarás 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 nuevo
MoveToEase(), llama a la función originalMoveToEase(), pasando todas las entradas másIdentityRotation()yVectorOnescomoScale.IdentityRotation()devuelve una rotación con cada valor en0, por tanto(0,0,0). Como no vas a añadir una rotación a tu animación, necesitarásIdentityRotation(). Tu función sobrecargadaMoveToEase()debería tener el siguiente aspecto: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 para crear otro método sobrecargado que solo cambie la rotación, y que mantenga la traslación y la escala sin cambios. Este nuevo método sobrecargado debería tener el siguiente aspecto:
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)Vuelve a repetir este paso para crear un método que solo cambie la escala, manteniendo igual la traslación y la rotación. No obstante, como
translationyscaleson ambosvector3, la función resultante tendría la misma firma que la sobrecarga que hiciste para la traslación, produciendo un error. Puedes solucionar esto reordenando los parámetros de la función. Intercambia la posición deDurationyScaley obtendrás tu función sobrecargada. El método sobrecargado debería tener el siguiente aspecto: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)Resulta muy útil tener una versión de
MoveToEase()que permita gestionar múltiples fotogramas clave. Puedes gestionarlo configurando tus fotogramas clave de antemano, y pasándolos todos aMoveToEase(). De este modo, la función solo necesita establecer y reproducir la animación en el elemento del modo Creativo. Añadir una nueva sobrecarga deMoveToEase()que toma como entrada una matriz de fotogramas clave y el modo de animación.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 el código y compílalo.
Una vez que hayas configurado tus métodos, ¡ha llegado el momento de iniciar el movimiento! En la siguiente sección, trasladarás elementos para crear plataformas móviles.
Código completo
A continuación encontrarás el código completo creado 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}