Mover Entities

Cómo mover, rotar y escalar una entity gradualmente con el tiempo, con cambios incrementales.

Para mover, rotar o redimensionar una entidad en tu escena durante un periodo de tiempo, usa el Tween component. El engine realiza la transformación deseada de forma suave, mostrando actualizaciones en cada frame hasta que se cumple la duración especificada. También los Transform component values de la entidad afectada se actualizan en tiempo real en caso de que sea necesario realizar comprobaciones de proximidad en el código de la escena.

circle-info

💡 Consejo: En el Scene Editor in Creator Hubarrow-up-right, puedes mover entidades de forma no-code mediante Actions, ver Make any item smartarrow-up-right.

El componente Tween tiene las siguientes funciones:

  • setMove: Mover entre dos puntos

  • setRotate: Rotar entre dos direcciones

  • setScale: Escalar entre dos tamaños

  • setMoveRotateScale: Transicionar simultáneamente en los tres parámetros

  • setMoveContinuous: Moverse constantemente en la misma dirección

  • setRotateContinuous: Rotar constantemente en la misma dirección

  • setTextureMove: Desplazar la textura de un material entre dos posiciones

  • setTextureMoveContinuous: Desplazar la textura de un material constantemente en la misma dirección

Mover entre dos puntos

Para mover una entidad entre dos puntos, crea un Tween component con la setMove function.

const myEntity = engine.addEntity()
Transform.create(myEntity, {
	position: Vector3.create(4, 1, 4),
})
MeshRenderer.setBox(myEntity)

Tween.setMove(myEntity, 
	Vector3.create(1, 1, 1), 
	Vector3.create(8, 1, 8), 
	2000
)

El tween de movimiento toma la siguiente información:

  • entity: La entidad a mover

  • start: Un Vector3 para la posición inicial

  • end: Un Vector3 para la posición final

  • duration: Cuántos milisegundos tarda en moverse entre las dos posiciones

Estos otros parámetros opcionales también están disponibles:

  • faceDirection: Si es true, la entidad se rota para mirar en la dirección del movimiento.

  • easingFunction: Qué función de easing usar. Ver Non-linear tweens

Rotar entre dos direcciones

Para rotar una entidad entre dos puntos, crea un Tween component con la setRotate function.

El tween de rotación toma la siguiente información:

  • start: Un Quaternion para la rotación inicial

  • end: Un Quaternion para la rotación final

  • duration: Cuántos milisegundos tarda en moverse entre las dos posiciones

Este otro parámetro opcional también está disponible:

Rotar con un punto pivote

Al rotar una entidad, la rotación siempre se realiza en referencia a la coordenada central de la entidad. Para rotar una entidad usando otro conjunto de coordenadas como punto pivote, crea una segunda entidad (invisible) con el punto pivote como su posición y hazla padre de la entidad que quieres rotar.

Al rotar la entidad padre, sus hijos se rotarán todos usando la posición del padre como punto pivote. Ten en cuenta que la position de la entidad hija está en referencia a la de la entidad padre.

Ten en cuenta que en este ejemplo, el sistema está rotando la pivotEntity entity, que es padre de la childEntity entity.

Escalar entre dos tamaños

Para cambiar la escala de una entidad entre dos tamaños, crea un Tween component con su modo establecido en Tween.Mode.Scale.

El tween de escala toma la siguiente información:

  • start: Un Vector3 para el tamaño inicial

  • end: Un Vector3 para el tamaño final

  • duration: Cuántos milisegundos tarda en moverse entre las dos posiciones

Este otro parámetro opcional también está disponible:

Non-linear tweens

Los tweens pueden seguir diferentes Easing Functions que afectan la tasa de cambio a lo largo del tiempo. Una linear function, significa que la velocidad del cambio es constante desde el inicio hasta el final. Hay muchas opciones para elegir, que dibujan curvas con diferentes formas dependiendo de si el comienzo y/o el final arrancan despacio, y cuánto. Una easeinexpo curve comienza despacio y termina rápido, incrementando la velocidad exponencialmente; por el contrario una easeoutexpo curve comienza rápido y termina despacio.

circle-info

💡 Consejo: Experimenta con diferentes curvas de movimiento. Las diferencias suelen ser sutiles, pero subconscientemente interpretamos información por cómo se mueven las cosas, como peso, fricción o incluso personalidad.

El parámetro opcional easingFunction toma su valor del EasingFunction enum, que ofrece las siguientes opciones:

  • EF_EASEBACK

  • EF_EASEBOUNCE

  • EF_EASECIRC

  • EF_EASECUBIC

  • EF_EASEELASTIC

  • EF_EASEEXPO

  • EF_EASEINBACK

  • EF_EASEINBOUNCE

  • EF_EASEINCIRC

  • EF_EASEINCUBIC

  • EF_EASEINELASTIC

  • EF_EASEINEXPO

  • EF_EASEINQUAD

  • EF_EASEINQUART

  • EF_EASEINQUINT

  • EF_EASEINSINE

  • EF_EASEOUTBACK

  • EF_EASEOUTBOUNCE

  • EF_EASEOUTCIRC

  • EF_EASEOUTCUBIC

  • EF_EASEOUTELASTIC

  • EF_EASEOUTEXPO

  • EF_EASEOUTQUAD

  • EF_EASEOUTQUART

  • EF_EASEOUTQUINT

  • EF_EASEOUTSINE

  • EF_EASEQUAD

  • EF_EASEQUART

  • EF_EASEQUINT

  • EF_EASESINE

  • EF_LINEAR

Rotación constante

Para hacer que una entidad rote constantemente, usa el Tween component con la setRotateContinuous function.

El tween de rotación continua toma la siguiente información:

  • entity: La entidad a rotar

  • direction: Un Quaternion para la rotación

  • speed: Cuántos grados por segundo rotará la entidad

Este otro parámetro opcional también está disponible:

  • duration: Cuántos milisegundos sostener la rotación. Después de ese tiempo, la rotación se detendrá.

Movimiento constante

Para hacer que una entidad se mueva constantemente en la misma dirección, usa el Tween component con la setMoveContinuous function.

El tween de movimiento continuo toma la siguiente información:

  • entity: La entidad a mover

  • direction: Un Vector3 para el movimiento

  • speed: Cuántos metros por segundo se moverá la entidad

Este otro parámetro opcional también está disponible:

  • duration: Cuántos milisegundos sostener el movimiento. Después de ese tiempo, el movimiento se detendrá.

El tween de movimiento continuo toma la siguiente información:

Secuencias de Tween

Para hacer que una entidad ejecute una serie de tweens en secuencia, usa el TweenSequence component. Este componente requiere dos campos:

  • sequence: Un array con múltiples definiciones de tween, que se ejecutarán secuencialmente. El array puede estar vacío, en cuyo caso sólo reproduce el tween actual.

  • loop (opcional): Si no se proporciona, la secuencia sólo se reproduce una vez. Si el campo está presente, el valor debe ser un valor del TweenLoop enum. Los valores aceptados son:

    • TL_RESTART: Cuando la secuencia termina, se reinicia. Si el último estado no coincide con el primer estado, la entidad salta instantáneamente de uno a otro.

    • TL_YOYO: Cuando la secuencia termina, retrocede, haciendo todos los tweens en reversa hasta que vuelve al inicio. Luego comienza de nuevo.

Mover de ida y vuelta

Para hacer que una plataforma se mueva constantemente de ida y vuelta entre dos posiciones, deja el sequence array vacío, y establece loop a TweenLoop.TL_YOYO

La entidad se moverá de un punto de inicio al punto final y de vuelta, con la misma duración y la misma función de easing en ambas direcciones.

Seguir un camino

Para hacer que una entidad siga un camino más complejo con múltiples puntos, proporciona una lista de definiciones de tween en la sequence de un TweenSequence component.

Ten en cuenta que al definir un tween dentro de un TweenSequence, necesitas usar el formato más verboso de Tween.Mode.Move, o Tween.Mode.Rotate, o Tween.Mode.Scale para definir el tween. En este formato más verboso, necesitas especificar:

  • duration: Cuántos milisegundos tarda en moverse entre las dos posiciones

  • easingFunction: Qué función de easing usar. Ver Non-linear tweens. En este formato el valor es requerido.

  • mode: El modo del tween, que puede ser Tween.Mode.Move, Tween.Mode.Rotate, o Tween.Mode.Scale.

Y dentro del campo mode debes especificar:

  • start: El valor inicial del tween

  • end: El valor final del tween

Al finalizar un tween

Usa tweenSystem.tweenCompleted para detectar cuando un tween ha terminado. Esto puede ser útil para realizar acciones cuando un tween termina, por ejemplo abrir la puerta de un ascensor.

Tweens simultáneos

Para mover, rotar y escalar una entidad entre un estado inicial y uno final, crea una Tween component con la setMoveRotateScale function. Esta función también puede usarse en cualquier combinación de estos tres parámetros.

El tween de movimiento toma la siguiente información:

  • entity: La entidad a mover

  • params: Un objeto con varios parámetros opcionales

    • position: Un objeto con un start y end value, ambos como Vector3.

    • rotation: Un objeto con un start y end value, ambos como Quaternion.

    • scale: Un objeto con un start y end value, ambos como Vector3.

    • duration: Cuántos milisegundos tarda en transicionar entre los dos conjuntos de valores

    • easingFunction: Qué función de easing usar. Ver Non-linear tweens

Una entidad sólo puede tener un Tween component, y cada componente tween sólo puede realizar una transformación a la vez. A través del setMoveRotateScale tween type, puedes hacer que una entidad se mueva lateralmente y también rote al mismo tiempo, pero ambos movimientos seguirán la misma línea temporal. Si necesitas que las transiciones sean independientes entre sí, como solución alternativa, puedes usar entidades parentadas. Por ejemplo, puedes tener una entidad padre invisible que se mueva lateralmente, con una hija visible que rote.

En el siguiente snippet, una entidad padre rota mientras una hija aumenta su escala.

Pausar un tween

Para pausar un tween, cambia la propiedad playing a false. Para reanudarlo, cámbiala de nuevo a true.

Para terminar un tween que no necesita continuar, elimina el Tween component de la entidad. Si la entidad también estaba usando un TweenSequence component, elimínalo también.

Tweens basados en un sistema

En lugar de usar el componente Tween y dejar que el engine maneje la transformación, puede que prefieras hacer esta transición de forma incremental, frame por frame, vía un systemarrow-up-right en tu escena. Moviendo la entidad una pequeña cantidad cada vez que la función se ejecuta.

Por un lado, esto te da más control para recalcular movimientos en cada frame. Por otro lado, el código es más complicado, y los jugadores con máquinas menos potentes podrían experimentar el tween como con latencia, notando cada incremento.

Mover vía system

La forma más sencilla de mover una entidad es modificar gradualmente el position valor almacenado en el Transform component.

En este ejemplo estamos moviendo una entidad 0.1 metros por tick del game loop.

Vector3.Forward() devuelve un vector que apunta hacia adelante y mide 1 metro de longitud. En este ejemplo estamos escalando este vector a 1/10 de su longitud con Vector3.scale(). Si nuestra escena tiene 30 frames por segundo, la entidad se mueve a 3 metros por segundo de velocidad.



Rotar vía system

La forma más sencilla de rotar una entidad es cambiar gradualmente los valores en el componente Transform de forma incremental, y ejecutar esto como parte de la función de un system.

Ten en cuenta que para combinar la rotación actual con cada incremento, estamos usando Quaternion.multiply. En matemáticas de cuaterniones, combinas dos rotaciones multiplicándolas, NO sumándolas. La rotación resultante de multiplicar un cuaternión por otro será la rotación final equivalente después de realizar primero una rotación y luego la otra.

En este ejemplo, estamos rotando la entidad 1 grado en dirección hacia arriba en cada tick del game loop.

circle-info

💡 Consejo: Para hacer que una entidad siempre rote para mirar al jugador, puedes añadir un Billboard componentarrow-up-right.



Rotar vía system sobre un punto pivote

Al rotar una entidad, la rotación siempre se realiza en referencia a la coordenada central de la entidad. Para rotar una entidad usando otro conjunto de coordenadas como punto pivote, crea una segunda entidad (invisible) con el punto pivote como su posición y hazla padre de la entidad que quieres rotar.

Al rotar la entidad padre, sus hijos se rotarán todos usando la posición del padre como punto pivote. Ten en cuenta que la position de la entidad hija está en referencia a la de la entidad padre.

Ten en cuenta que en este ejemplo, el sistema está rotando la pivotEntity entity, que es padre de la childEntity entity.



Ajustar el movimiento según el tiempo de retardo

Supón que el jugador que visita tu escena tiene dificultades para seguir el ritmo del frame rate. Eso podría resultar en que el movimiento aparezca entrecortado, ya que no todos los frames están igualmente espaciados pero cada uno mueve la entidad en la misma cantidad.

Puedes compensar este tiempo desigual usando el dt parámetro para ajustar la escala del movimiento.

El ejemplo anterior mantiene el movimiento aproximadamente a la misma velocidad que el ejemplo de movimiento anterior, incluso si la tasa de frames baja. Al ejecutarse a 30 frames por segundo, el valor de dt es 1/30.

También puedes suavizar rotaciones de la misma manera multiplicando la cantidad de rotación por dt.

Mover entre dos puntos vía system

Si quieres que una entidad se mueva suavemente entre dos puntos, usa el lerp (interpolación lineal) algoritmo. Este algoritmo es muy conocido en el desarrollo de juegos, ya que es realmente útil.

La lerp() function toma tres parámetros:

  • El vector para la posición de origen

  • El vector para la posición objetivo

  • La cantidad, un valor de 0 a 1 que representa qué fracción de la traslación realizar.

El algoritmo de interpolación lineal encuentra un punto intermedio en el camino entre ambos vectores que coincide con la cantidad proporcionada.

Por ejemplo, si el vector de origen es (0, 0, 0) y el vector objetivo es (10, 0, 10):

  • Usar una cantidad de 0 retornaría (0, 0, 0)

  • Usar una cantidad de 0.3 retornaría (3, 0, 3)

  • Usar una cantidad de 1 retornaría (10, 0, 10)

Para implementar esto lerp() en tu escena, recomendamos crear un custom componentarrow-up-right para almacenar la información necesaria. También necesitas definir un system que implemente el movimiento gradual en cada frame.



Rotar entre dos ángulos vía system

Para rotar suavemente entre dos ángulos, usa el slerp (esférico interpolación lineal) algoritmo. Este algoritmo es muy similar a un lerp, pero maneja rotaciones quaternion.

La slerp() function toma tres parámetros:

circle-info

💡 Consejo: Puedes pasar valores de rotación en eulerarrow-up-right grados (de 0 a 360) usando Quaternion.fromEulerDegrees().

Para implementar esto en tu escena, recomendamos almacenar los datos que alimentan la Slerp() function en un custom componentarrow-up-right. También necesitas definir un system que implemente la rotación gradual en cada frame.

circle-exclamation


Un enfoque más simple pero menos eficiente para esto se aprovecha de la Quaternion.rotateTowards función, y evita el uso de cualquier componente personalizado.

En el ejemplo anterior Quaternion.rotateTowards toma tres argumentos: la rotación inicial, la rotación final deseada y el incremento máximo por frame. En este caso, dado que el incremento máximo es de dt * 10 grados, la rotación se realizará durante un período de un par de 9 segundos.

Tenga en cuenta que el sistema también verifica si la rotación está completa y, de ser así, elimina el sistema del engine. De lo contrario, el sistema seguiría realizando cálculos en cada frame, incluso una vez completada la rotación.

Cambiar la escala entre dos tamaños mediante un system

Si desea que una entidad cambie de tamaño de forma suave y sin cambiar sus proporciones, utilice la lerp (interpolación lineal) del algoritmo de Scalar objeto.

De lo contrario, si desea cambiar los ejes en proporciones diferentes, use Vector3 para representar la escala de origen y la escala objetivo, y luego use la lerp función del Vector3.

La lerp() función del Scalar objeto toma tres parámetros:

  • Un número para la escala de origen

  • Un número para la escala objetivo

  • La cantidad, un valor de 0 a 1 que representa qué fracción del escalado realizar.

Para implementar este lerp en su escena, recomendamos crear un componente personalizado para almacenar la información necesaria. También necesita definir un system que implemente el escalado gradual en cada frame.



Moverse a velocidades irregulares entre dos puntos mediante un system

Mientras se usa el método lerp, puede hacer que la velocidad de movimiento sea no lineal. En el ejemplo anterior incrementamos la cantidad del lerp en un valor dado cada frame, pero también podríamos usar una función matemática para aumentar el número exponencialmente u otras medidas que le den un ritmo de movimiento diferente.

También podría usar una función que dé resultados recurrentes, como una función seno, para describir un movimiento que va y viene.

A menudo estas transiciones no lineales pueden aportar mucha vida a una escena. Un movimiento que acelera a lo largo de una curva o se desacelera gradualmente puede decir mucho sobre la naturaleza de un objeto o personaje. Incluso podría aprovechar funciones matemáticas que añadan efectos de rebote.

El ejemplo anterior es igual al ejemplo de lerp lineal que mostramos antes, pero el fraction campo se mapea a un valor no lineal en cada tick. Este valor no lineal se usa para calcular la lerp función, resultando en un movimiento que sigue una curva exponencial.

También puede mapear una transición en rotación o en escala de la misma manera que se muestra arriba, mapeando una transición lineal a una curva.



Seguir un camino mediante un system

Puede hacer que una entidad recorra en bucle un array de vectores, realizando un movimiento lerp entre cada uno para seguir un camino más complejo.

El ejemplo anterior define un camino 3D compuesto por cuatro vectores 3D. El PathTransportData componente personalizado contiene los mismos datos usados por el componente personalizado en el lerp ejemplo anterior, pero añade un path array, con todos los puntos de nuestro camino, y un pathTargetIndex campo para hacer un seguimiento de qué segmento del camino se está usando actualmente.

El sistema es muy similar al sistema en el lerp ejemplo, pero cuando se completa una acción de lerp, establece los target y origin campos en nuevos valores. Si llegamos al final del camino, volvemos al primer valor del camino.



Tweens de textura

Para hacer que una textura se deslice suavemente, use el Tween component con la setTextureMove function.

El tween de textura toma la siguiente información:

  • entity: La entidad cuya textura se moverá

  • start: Un Vector2 para la posición inicial

  • end: Un Vector2 para la posición final

  • duration: Cuántos milisegundos tarda en moverse entre las dos posiciones

Este otro parámetro opcional también está disponible:

  • movementType: (opcional), define si el movimiento será en el campo offset o en el campo tiling. Por defecto usa offset.

  • easingFunction: Qué función de easing usar. Ver Non-linear tweens. Nota: Este parámetro solo se usa si se proporciona una duración.

Movimiento constante de textura

Para hacer que una textura se deslice constantemente, use el Tween component con la setTextureMoveContinuous function.

El tween continuo de textura toma la siguiente información:

  • entity: La entidad cuya textura se moverá

  • direction: Un Vector2 para el movimiento

  • speed: Cuántas unidades por segundo se moverá la entidad

Este otro parámetro opcional también está disponible:

  • movementType: define si el movimiento será en el campo offset o en el campo tiling. Por defecto usa offset.

  • duration: Cuántos milisegundos sostener el movimiento. Después de ese tiempo, el movimiento se detendrá.

Lea más sobre los tweens de textura en el Texture Tweensarrow-up-right apartado.

Última actualización