Mover Entities
Cómo mover, rotar y escalar una entidad gradualmente con el tiempo, con cambios incrementales.
Para mover, rotar o redimensionar una Entity en tu scene 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 termina la duración especificada. Además, los Transform valores del component de la entidad afectada se actualizan en tiempo real en caso de que sea necesario hacer comprobaciones de proximidad en el código de la scene.
El component Tween tiene las siguientes funciones:
setMove: Mover entre dos puntossetRotate: Rotar entre dos direccionessetScale: Escalar entre dos tamañossetMoveRotateScale: Transicionar simultáneamente en los tres parámetrossetMoveContinuous: Moverse constantemente en la misma direcciónsetRotateContinuous: Rotar constantemente en la misma direcciónsetTextureMove: Desplazar la textura de un material entre dos posicionessetTextureMoveContinuous: 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 función.
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 moverstart: Un Vector3 para la posición inicialend: Un Vector3 para la posición finalduration: Cuántos milisegundos tarda en moverse entre las dos posiciones
También está disponible este otro parámetro opcional:
easingFunction: Qué función de easing usar. Consulta Tweens no lineales
Rotar entre dos direcciones
Para rotar una entidad entre dos puntos, crea un Tween component con la setRotate función.
El tween de rotación toma la siguiente información:
start: Un Quaternion para la rotación inicialend: Un Quaternion para la rotación finalduration: Cuántos milisegundos tarda en moverse entre las dos posiciones
También está disponible este otro parámetro opcional:
easingFunction: Qué función de easing usar. Consulta Tweens no lineales
Rotar con un punto de pivote
Al rotar una entidad, la rotación siempre toma como referencia la coordenada central de la entidad. Para rotar una entidad usando otro conjunto de coordenadas como punto de pivote, crea una segunda entidad (invisible) con el punto de pivote como su posición y haz que sea padre de la entidad que quieres rotar.
Al rotar la entidad padre, todas sus hijas se rotarán usando la posición del padre como punto de pivote. Ten en cuenta que la position de la entidad hija toma como referencia la de la entidad padre.
Ten en cuenta que en este ejemplo, el system está rotando la entidad pivotEntity que es padre de la entidad childEntity .
Escalar entre dos tamaños
Para cambiar la escala de una entidad entre dos tamaños, crea un Tween component con la setScale función.
El tween de escala toma la siguiente información:
start: Un Vector3 para el tamaño inicialend: Un Vector3 para el tamaño finalduration: Cuántos milisegundos tarda en moverse entre las dos posiciones
También está disponible este otro parámetro opcional:
easingFunction: Qué función de easing usar. Consulta Tweens no lineales
Mover desde la posición actual
Mientras un tween está activo, el engine actualiza los Transform valores del component de la entidad en tiempo real. Esto significa que puedes leer la posición actual de la entidad desde su Transform component en cualquier momento, y usar ese valor como el start de un nuevo tween. Entonces la entidad se mueve desde donde esté en ese momento hasta el destino, sin importar cómo llegó allí.
📔 Nota: Pasa siempre un start valor explícito. Si el start parámetro se deja sin establecer, se trata como (0, 0, 0), así que la entidad se teletransporta al origen de la scene antes de moverse. Del mismo modo, si pasas un start codificado manualmente que no coincide con la posición actual de la entidad, la entidad se teletransporta visiblemente a esa posición antes de moverse. Lee la posición actual desde el Transform component de la entidad, como en los ejemplos de esta sección, siempre que quieras que el movimiento comience desde donde está actualmente la entidad.
Cambiar el objetivo mientras viaja
Llamar a setMove (o a cualquiera de las otras funciones de tween) sobre una entidad que ya tiene un tween en ejecución reemplaza el tween en ejecución por el nuevo. Como la start se lee desde la posición en vivo de la entidad, esto redirige la entidad suavemente a mitad del viaje: cambia de rumbo desde donde está en ese momento, sin saltos.
El ejemplo de abajo mueve una entidad hacia la plataforma que el jugador haga clic. Si el jugador hace clic en otra plataforma mientras la entidad sigue viajando, la entidad cambia de dirección suavemente hacia el nuevo objetivo.
Para ejecutar lógica cuando la entidad llegue a su destino, consulta Al terminar el tween.
📔 Nota: Reorienta de esta manera solo como respuesta a eventos ocasionales, como un clic o al llegar a un waypoint. Si el objetivo cambia constantemente, por ejemplo una entidad que sigue al jugador, no crees un nuevo tween en cada frame: la entidad sufrirá tirones visibles. Consulta Seguir un objetivo en movimiento.
Tweens no lineales
Los tweens pueden seguir diferentes Easing Functions que afectan la tasa de cambio con el tiempo. Una lineal función significa que la velocidad del cambio es constante de principio a fin. Hay muchas opciones para elegir, que dibujan curvas con formas diferentes dependiendo de si el inicio y/o el final comienzan lento, y cuánto. Una curva easeinexpo comienza lenta y termina rápida, aumentando la velocidad exponencialmente; por el contrario, una curva easeoutexpo comienza rápida y termina lenta.
El easingFunction parámetro opcional toma su valor de la EasingFunction enum, que ofrece las siguientes opciones:
EF_EASEBACKEF_EASEBOUNCEEF_EASECIRCEF_EASECUBICEF_EASEELASTICEF_EASEEXPOEF_EASEINBACKEF_EASEINBOUNCEEF_EASEINCIRCEF_EASEINCUBICEF_EASEINELASTICEF_EASEINEXPOEF_EASEINQUADEF_EASEINQUARTEF_EASEINQUINTEF_EASEINSINEEF_EASEOUTBACKEF_EASEOUTBOUNCEEF_EASEOUTCIRCEF_EASEOUTCUBICEF_EASEOUTELASTICEF_EASEOUTEXPOEF_EASEOUTQUADEF_EASEOUTQUARTEF_EASEOUTQUINTEF_EASEOUTSINEEF_EASEQUADEF_EASEQUARTEF_EASEQUINTEF_EASESINEEF_LINEAR
Rotación constante
Para hacer que una entidad rote constantemente, usa el Tween component con la setRotateContinuous función.
El tween de rotación continua toma la siguiente información:
entity: La entidad a rotardirection: Un Quaternion que determina el eje alrededor del cual rotar. Solo importa el eje de esta rotación; el tamaño de su ángulo se ignora. Por ejemplo,Quaternion.fromEulerDegrees(0, -1, 0)yQuaternion.fromEulerDegrees(0, -90, 0)se comportan igual, ambos girando alrededor del eje y en dirección negativa.speed: Cuántos grados por segundo rotará la entidad. Un valor negativo rota en la dirección opuesta.
También está disponible este otro parámetro opcional:
duration: Cuántos milisegundos debe mantenerse la rotación. Después de este 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 función.
El tween de movimiento continuo toma la siguiente información:
entity: La entidad a moverdirection: Un Vector3 para el movimientospeed: Cuántos metros por segundo se moverá la entidad
También está disponible este otro parámetro opcional:
duration: Cuántos milisegundos debe mantenerse el movimiento. Después de este tiempo, el movimiento se detendrá.
El tween de movimiento continuo toma la siguiente información:
Seguir un objetivo en movimiento
setMoveContinuous también es la herramienta adecuada cuando el destino sigue cambiando, por ejemplo una entidad que sigue al jugador. Puede resultar tentador crear en su lugar un nuevo setMove tween en cada frame, apuntando a la última posición del jugador, pero eso produce un tirón visible.
La razón es que la posición que lees del Transform component de una entidad con tween es la posición que el engine informó por última vez a la scene, así que va con unos pocos frames de retraso respecto a dónde está realmente la entidad. Cuando pasas ese valor como el start de un nuevo tween, el engine lo aplica de inmediato y la entidad salta de vuelta a donde estaba hace unos pocos frames. Una de esas correcciones es imperceptible, pero repetirla muchas veces por segundo no lo es.
setMoveContinuous evita el problema por completo, porque le das una dirección y una velocidad en lugar de un punto de partida. El engine sigue usando la posición real de la entidad, así que reemplazar el tween para cambiar de dirección nunca hace que la entidad salte.
📔 Nota: Un tween continuo nunca termina por sí solo, así que la entidad sigue moviéndose hasta que elimines el Tween component con Tween.deleteFrom(), o hasta que se agote el duration opcional. Ten en cuenta también que volver a apuntar en cada frame envía una actualización al engine en cada frame. Para evitarlo, solo llama a setMoveContinuous de nuevo cuando la dirección haya cambiado lo suficiente como para importar.
Secuencias de Tween
Para hacer que una entidad reproduzca una serie de tweens en secuencia, usa el TweenSequence component. Este component requiere dos campos:
sequence: Un array con múltiples definiciones de tween, que se ejecutarán secuencialmente. El array puede estar vacío; en ese caso solo reproduce el tween actual.loop(opcional): Si no se proporciona, la secuencia solo se reproduce una vez. Si el campo está presente, el valor debe ser un valor de laTweenLoopenum. Los valores aceptados son:TL_RESTART: Cuando termina la secuencia, se reinicia. Si el último estado no coincide con el primero, la entidad salta instantáneamente de uno a otro.TL_YOYO: Cuando termina la secuencia, retrocede, haciendo todos los tweens en orden inverso hasta volver a llegar al inicio. Luego comienza una vez más.
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 en TweenLoop.TL_YOYO
La entidad se moverá de ida y vuelta entre el punto inicial y el punto final, con la misma duración y la misma función de easing en ambas direcciones.
Seguir una ruta
Para hacer que una entidad siga una ruta más compleja con múltiples puntos, proporciona una lista de definiciones de tween en el sequence de un TweenSequence component.
Ten en cuenta que, al definir un tween dentro de un TweenSequence, necesitas usar el formato más detallado de Tween.Mode.Move, o Tween.Mode.Rotate, o Tween.Mode.Scale para definir el tween. En este formato más detallado, necesitas especificar:
duration: Cuántos milisegundos tarda en moverse entre las dos posicioneseasingFunction: Qué función de easing usar. Consulta Tweens no lineales. En este formato, el valor es obligatorio.mode: El modo del tween, que puede serTween.Mode.Move,Tween.Mode.Rotate, oTween.Mode.Scale.
Y dentro del campo mode field, necesitas especificar:
start: El valor inicial del tweenend: El valor final del tween
Al terminar el tween
Usa tweenSystem.tweenCompleted para detectar cuándo ha terminado un tween. Esto puede ser útil para realizar acciones cuando un tween finaliza, por ejemplo para 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 función. 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 moverparams: Un objeto con los siguientes parámetrosposition: (opcional) Un objeto con unstartyendvalor, ambos comoVector3.rotation: (opcional) Un objeto con unstartyendvalor, ambos comoQuaternion.scale: (opcional) Un objeto con unstartyendvalor, ambos comoVector3. Al menos uno deposition,rotationoscaledebe proporcionarse.duration: (obligatorio) Cuántos milisegundos tarda en transicionar entre los dos conjuntos de valoreseasingFunction: (opcional) Qué función de easing usar. Consulta Tweens no lineales
Una entity solo puede tener un Tween component, y cada Tween component solo puede realizar una transformación a la vez. A través del setMoveRotateScale tipo de tween, puedes hacer que una entity se mueva lateralmente y también gire al mismo tiempo, pero ambos movimientos seguirán la misma línea de tiempo. Si necesitas que las transiciones sean independientes entre sí, como solución alternativa, puedes usar entities con parent. Por ejemplo, puedes tener una entity parent invisible que se mueve lateralmente, con una child visible que gira.
En el siguiente fragmento, una entity parent gira mientras una child se escala.
Pausar un tween
Para pausar un tween, cambia la playing propiedad a false. Para reanudarlo, vuelve a cambiarla a true.
Para terminar un tween que no necesita continuar, elimina el Tween component de la entity. Si la entity también estaba usando un TweenSequence component, elimina ese también.
Tweens basados en un system
En lugar de usar el Tween component y dejar que el engine se encargue de la transformación, quizá prefieras hacer esta transición de forma incremental, frame a frame, mediante un system en tu scene. Al mover la entity una pequeña cantidad cada vez que se ejecuta la función.
Por un lado, esto te da más control para recalcular los movimientos en cada frame. Por otro lado, el código es más complicado, y los players con máquinas menos potentes podrían experimentar el tween como lento, notando cada incremento.
Mover mediante system
La forma más sencilla de mover una entity es modificar gradualmente el position valor almacenado en la Transform component.
En este ejemplo estamos moviendo una entity 0,05 metros por tick del game loop.
Vector3.Forward() devuelve un vector que apunta hacia adelante y mide 1 metro de longitud. En este ejemplo luego reducimos este vector a 1/20 de su longitud con Vector3.scale(). Si nuestra scene tiene 30 frames por segundo, la entity se está moviendo a una velocidad de 1,5 metros por segundo.

Rotar mediante system
La forma más sencilla de rotar una entity es cambiar gradualmente los valores del Transform component 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ática de quaternion, combinas dos rotaciones multiplicándolas, NO sumándolas. La rotación resultante de multiplicar un quaternion por otro será la rotación final equivalente tras realizar primero una rotación y luego la otra.
En este ejemplo, estamos rotando la entity 1 grado en dirección ascendente en cada tick del game loop.

Rotar mediante system sobre un punto de pivote
Al rotar una entidad, la rotación siempre toma como referencia la coordenada central de la entidad. Para rotar una entidad usando otro conjunto de coordenadas como punto de pivote, crea una segunda entidad (invisible) con el punto de pivote como su posición y haz que sea padre de la entidad que quieres rotar.
Al rotar la entidad padre, todas sus hijas se rotarán usando la posición del padre como punto de pivote. Ten en cuenta que la position de la entidad hija toma como referencia la de la entidad padre.
Ten en cuenta que en este ejemplo, el system está rotando la entidad pivotEntity que es padre de la entidad childEntity .

Ajustar el movimiento al tiempo de retraso
Supón que el player que visita tu scene tiene dificultades para seguir el ritmo del frame rate. Eso podría hacer que el movimiento se vea entrecortado, ya que no todos los frames están espaciados uniformemente, pero cada uno mueve la entity la misma cantidad.
Puedes compensar este espaciado irregular 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 el frame rate baja. Cuando se ejecuta a 30 frames por segundo, el valor de dt es 1/30.
También puedes suavizar las rotaciones de la misma manera multiplicando la cantidad de rotación por dt.
Mover entre dos points mediante system
Si quieres que una entity se mueva suavemente entre dos points, usa el lerp (linear interpolation) algorithm. Este algorithm es muy conocido en el desarrollo de videojuegos, ya que es realmente útil.
El lerp() function toma tres parámetros:
El vector para la posición de origen
El vector para la posición de destino
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 recorrido entre ambos vectors que coincide con la cantidad proporcionada.
Por ejemplo, si el vector de origen es (0, 0, 0) y el vector de destino es (10, 0, 10):
Usar una cantidad de 0 devolvería (0, 0, 0)
Usar una cantidad de 0,3 devolvería (3, 0, 3)
Usar una cantidad de 1 devolvería (10, 0, 10)
Para implementar esto lerp() en tu scene, recomendamos crear un custom component para almacenar la información necesaria. También necesitas definir un system que implemente el movimiento gradual en cada frame.

Rotar entre dos ángulos mediante system
Para rotar suavemente entre dos ángulos, usa el slerp (esférica (linear interpolation) algorithm. Este algorithm es muy similar a un lerp, pero maneja rotaciones de quaternion.
El slerp() function toma tres parámetros:
El quaternion angle para la rotación de origen
El quaternion angle para la rotación de destino
La cantidad, un valor de 0 a 1 que representa qué fracción de la traslación realizar.
Para implementar esto en tu scene, te recomendamos almacenar los datos que van a la Slerp() function en un custom component. También necesitas definir un system que implemente la rotación gradual en cada frame.
📔 Nota: Podrías representar la rotation con euler angles como Vector3 values y usar una Lerp() function, pero eso implicaría una conversión desde Vector3 en Quaternion en cada frame. Los valores de rotation se almacenan internamente como quaternions en el Transform component, así que es más eficiente que la scene trabaje con quaternions.

Un enfoque más simple, pero menos eficiente, aprovecha la Quaternion.rotateTowards function, y evita usar cualquier custom component.
En el example anterior Quaternion.rotateTowards takes three arguments: the initial rotation, the final rotation that's desired, and the maximum increment per frame. In this case, since the maximum increment is of dt * 10 degrees, la rotación se llevará a cabo durante un período de un par de 9 seconds.
Ten en cuenta que el system también comprueba si la rotación está completa y, si es así, elimina el system del engine. De lo contrario, el system seguiría haciendo cálculos en cada frame, incluso una vez que la rotación está completa.
Cambiar la scale entre dos sizes mediante system
Si quieres que una entity cambie de size suavemente y sin cambiar sus proportions, usa el lerp (linear interpolation) algorithm del Scalar object.
De lo contrario, si quieres cambiar los ejes en proporciones diferentes, usa Vector3 para representar la origin scale y la target scale, y luego usa la lerp function del Vector3.
El lerp() function del Scalar object toma tres parámetros:
Un number para la origin scale
Un number para la target scale
La cantidad, un valor de 0 a 1 que representa qué fracción del scaling realizar.
Para implementar este lerp en tu scene, te recomendamos crear un custom component para almacenar la información necesaria. También necesitas definir un system que implemente el escalado gradual en cada frame.

Mover a velocidades irregulares entre dos points mediante system
Mientras usas el método lerp, puedes hacer que la velocidad del movimiento sea no lineal. En el ejemplo anterior incrementamos la cantidad de lerp en una cantidad dada en cada frame, pero también podríamos usar una función matemática para aumentar el número exponencialmente o con otras medidas que te den un ritmo de movimiento diferente.
También podrías 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 dar mucha vida a una scene. Un movimiento que acelera a lo largo de una curve o desacelera gradualmente puede decir mucho sobre la nature de un object or character. Incluso podrías aprovechar funciones matemáticas que añadan efectos de rebote.
El ejemplo anterior es igual que el ejemplo de lerp lineal que hemos mostrado 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, lo que da como resultado un movimiento que sigue una curva exponencial.
También puedes mapear una transición en rotation o en scale de la misma manera que se muestra arriba, mapeando una transición lineal a una curve.

Seguir un path mediante system
Puedes hacer que una entity recorra en loop un array de vectors, realizando un movimiento lerp entre cada uno para seguir un path más compleja.
El ejemplo anterior define un path 3D compuesto por cuatro vectors 3D. El PathTransportData custom component contiene los mismos datos usados por el custom component en el lerp example anterior, pero añade un path array, con todos los points de nuestro path, y un pathTargetIndex field para hacer seguimiento de qué segment del path está actualmente en use.
El system es muy similar al system del lerp example, pero cuando se completa una acción lerp, establece los target y origin fields con nuevos values. Si alcanzamos el end del path, volvemos al primer value del path.

Tweens de texture
Para hacer que una texture se deslice suavemente, usa el Tween component con la setTextureMove función.
El texture tween toma la siguiente information:
entity: La entity de la que mover la texturestart: Un Vector2 para la starting positionend: Un Vector2 para la ending positionduration: Cuántos milisegundos tarda en moverse entre las dos posiciones
También está disponible este otro parámetro opcional:
movementType: (opcional), define si el movement será en el field offset o el field tiling. Por defecto usa offset.easingFunction: Qué función de easing usar. Consulta Tweens no lineales.
Movimiento constante de texture
Para hacer que una texture se deslice constantemente, usa el Tween component con la setTextureMoveContinuous función.
El texture continuous tween toma la siguiente information:
entity: La entity de la que mover la texturedirection: Un Vector2 para el movementspeed: Cuántas units per second se moverá la entity
También está disponible este otro parámetro opcional:
movementType: define si el movement será en el field offset o el field tiling. Por defecto usa offset.duration: Cuántos milisegundos debe mantenerse el movimiento. Después de este tiempo, el movimiento se detendrá.
Lee más sobre texture tweens en la Texture Tweens section.
Última actualización