> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/fundamentos-del-contenido-3d/move-entities.md).

# Mover entidades

Cómo mover, rotar y escalar una entidad gradualmente a lo largo del tiempo, con cambios incrementales.

Para mover, rotar o cambiar el tamaño de una entidad en tu escena durante un periodo de tiempo, usa el `Tween` componente. El motor realiza la transformación deseada suavemente, mostrando actualizaciones en cada frame hasta que termina la duración especificada. Además, el `Transform` component values of the affected entity gets updated in real time in case it's needed to make proximity checks in the scene code.

{% hint style="info" %}
**💡 Consejo**: En el [Scene Editor en Creator Hub](/creator/content-creator-es/scene-editor/primeros-pasos/about-editor.md), puedes mover entidades sin código mediante **Actions**, consulta [Convierte cualquier item en smart](/creator/content-creator-es/scene-editor/interactividad/make-any-item-smart.md).
{% endhint %}

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` componente con el `setMove` función.

```ts
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:

* `entidad`: La entidad a mover
* `start`: Un Vector3 para la posición inicial
* `end`: Un Vector3 para la posición final
* `duración`: Cuántos milisegundos tarda en moverse entre las dos posiciones

También está disponible este otro parámetro opcional:

* `easingFunction`: Qué función easing usar. Ver [Tweens no lineales](#non-linear-tweens)

## Rotar entre dos direcciones

Para rotar una entidad entre dos puntos, crea un `Tween` componente con el `setRotate` función.

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

Tween.setRotate(myEntity, 
	Quaternion.fromEulerDegrees(0, 0, 0), 
	Quaternion.fromEulerDegrees(0, 170, 0), 
	700
)
```

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
* `duración`: Cuántos milisegundos tarda en moverse entre las dos posiciones

También está disponible este otro parámetro opcional:

* `easingFunction`: Qué función easing usar. Ver [Tweens no lineales](#non-linear-tweens)

### Rotar con un punto de pivote

Cuando rotas 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 posición y haz que sea una entidad padre de la entidad que quieres rotar.

Al rotar la entidad padre, todas sus entidades hijas se rotarán usando la posición del padre como punto de pivote. Ten en cuenta que el `posición` de la entidad hija está en referencia a la de la entidad padre.

```ts
const pivotEntity = engine.addEntity()
Transform.create(pivotEntity, {
	position: Vector3.create(4, 1, 4),
})

const childEntity = engine.addEntity()
Transform.create(childEntity, {
	position: Vector3.create(1, 0, 0),
	parent: pivotEntity,
})
MeshRenderer.setBox(childEntity)

Tween.setRotate(pivotEntity, 
	Quaternion.fromEulerDegrees(0, 0, 0), 
	Quaternion.fromEulerDegrees(0, 170, 0), 
	700
)
```

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

## Escalar entre dos tamaños

Para cambiar la escala de una entidad entre dos tamaños, crea un `Tween` componente con el `setScale` función.

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

Tween.setScale(myEntity, 
	Vector3.create(1, 1, 1), 
	Vector3.create(4, 4, 4), 
	2000
)	

```

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
* `duración`: Cuántos milisegundos tarda en moverse entre las dos posiciones

También está disponible este otro parámetro opcional:

* `easingFunction`: Qué función easing usar. Ver [Tweens no lineales](#non-linear-tweens)

## Mover desde la posición actual

Mientras un tween está activo, el motor actualiza los `Transform` valores del componente de la entidad en tiempo real. Esto significa que puedes leer la posición actual de la entidad desde su `Transform` componente en cualquier momento, y usar ese valor como el `start` de un nuevo tween. Entonces la entidad se mueve desde donde esté actualmente hasta el objetivo, sin importar cómo haya llegado allí.

```ts
pointerEventsSystem.onPointerDown(
	{
		entity: myEntity,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Mover' },
	},
	() => {
		Tween.setMove(myEntity, 
			Transform.get(myEntity).position, 
			Vector3.create(8, 1, 8), 
			2000,
			EasingFunction.EF_EASEOUTQUAD
		)
	}
)
```

{% hint style="warning" %}
**📔 Nota**: Pasa siempre un `start` valor explícito. Si el `start` parámetro se deja sin establecer, se trata como *(0, 0, 0)*, por lo que la entidad se teletransporta al origen de la escena antes de moverse. Del mismo modo, si pasas un `start` 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` componente, como en los ejemplos de esta sección, siempre que quieras que el movimiento comience desde donde está actualmente la entidad.
{% endhint %}

### Reorientar durante el viaje

Llamar a `setMove` (o cualquiera de las otras funciones tween) en una entidad que ya tiene un tween en ejecución reemplaza el tween en ejecución por el nuevo. Como el `start` se lee desde la posición en vivo de la entidad, esto redirige la entidad suavemente a mitad del trayecto: cambia de rumbo desde donde esté en ese momento, sin ningún salto.

El siguiente ejemplo mueve una entidad hasta la plataforma que el jugador pulse. Si el jugador pulsa otra plataforma mientras la entidad sigue viajando, la entidad cambia suavemente de dirección hacia el nuevo objetivo.

```ts
function moveTo(target: Vector3) {
	Tween.setMove(shipEntity, 
		Transform.get(shipEntity).position, 
		target, 
		2000,
		EasingFunction.EF_EASEOUTQUAD
	)
}

pointerEventsSystem.onPointerDown(
	{
		entity: padA,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Mover aquí' },
	},
	() => moveTo(Vector3.create(2, 1, 2))
)

pointerEventsSystem.onPointerDown(
	{
		entity: padB,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Mover aquí' },
	},
	() => moveTo(Vector3.create(14, 1, 14))
)
```

Para ejecutar lógica cuando la entidad llegue a su destino, consulta [Al finalizar el tween](#on-tween-finished).

{% hint style="warning" %}
**📔 Nota**: Reorienta de esta manera solo en 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](#follow-a-moving-target).
{% endhint %}

## Tweens no lineales

Los tweens pueden seguir distintos **Funciones easing** que afectan la velocidad 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 de distintas formas según si el comienzo y/o el final empiezan despacio, y cuánto. Un **easeinexpo** curva empieza lenta y termina rápido, aumentando la velocidad exponencialmente; por el contrario, una **easeoutexpo** curva empieza rápido y termina lento.

{% hint style="info" %}
**💡 Consejo**: Experimenta con distintas curvas de movimiento. Las diferencias suelen ser sutiles, pero interpretamos de forma subconsciente la información a partir de cómo se mueven las cosas, como el peso, la fricción o incluso la personalidad.
{% endhint %}

```ts
Tween.setScale(myEntity, 
	Vector3.create(1, 1, 1), 
	Vector3.create(4, 4, 4), 
	2000,
	EasingFunction.EF_EASEOUTBOUNCE
)

```

El parámetro opcional `easingFunction` toma su valor de la `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` componente con el `setRotateContinuous` función.

```ts
Tween.setRotateContinuous(myEntity, 
	Quaternion.fromEulerDegrees(0, -1, 0), 
	45
)
```

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

* `entidad`: La entidad a rotar
* `dirección`: Un Quaternion que determina el eje alrededor del cual rotar. Solo importa el eje de esta rotación; se ignora el tamaño de su ángulo. Por ejemplo, `Quaternion.fromEulerDegrees(0, -1, 0)` y `Quaternion.fromEulerDegrees(0, -90, 0)` se comportan igual, ambos rotando alrededor del *y* eje 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:

* `duración`: Cuántos milisegundos mantener 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` componente con el `setMoveContinuous` función.

```ts
Tween.setMoveContinuous(myEntity, 
	Vector3.create(0, 0, 1), 
	0.7
)
```

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

* `entidad`: La entidad a mover
* `dirección`: Un Vector3 para el movimiento
* `speed`: Cuántos metros por segundo se moverá la entidad

También está disponible este otro parámetro opcional:

* `duración`: Cuántos milisegundos mantener el movimiento. Después de ese 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. Es tentador crear en su lugar un nuevo `setMove` tween en cada frame, apuntando a la posición más reciente del jugador, pero eso produce un tirón visible.

La razón es que la posición que lees del `Transform` componente de una entidad con tween es la posición que el motor informó por última vez a la escena, por lo que va unos frames por detrás de donde la entidad realmente está. Cuando pasas ese valor como el `start` de un nuevo tween, el motor lo aplica inmediatamente, y la entidad salta hacia atrás a donde estaba hace unos 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 motor 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.

```ts
const CHASE_SPEED = 3
const STOP_DISTANCE = 1

engine.addSystem(() => {
	const playerPosition = Transform.get(engine.PlayerEntity).position
	const myPosition = Transform.get(myEntity).position

	if (Vector3.distance(myPosition, playerPosition) <= STOP_DISTANCE) {
		// Lo suficientemente cerca: un tween continuo no tiene destino, así que lo detienes tú mismo
		if (Tween.has(myEntity)) {
			Tween.deleteFrom(myEntity)
		}
		return
	}

	const direction = Vector3.subtract(playerPosition, myPosition)
	direction.y = 0 // permanece en el suelo, incluso si el jugador salta

	Tween.setMoveContinuous(myEntity, Vector3.normalize(direction), CHASE_SPEED)
})
```

{% hint style="warning" %}
**📔 Nota**: Un tween continuo nunca termina por sí solo, así que la entidad sigue moviéndose hasta que elimines el `Tween` componente con `Tween.deleteFrom()`, o hasta que el opcional `duración` se agote. Ten en cuenta también que volver a apuntar en cada frame envía una actualización al motor en cada frame. Para evitarlo, solo llama a `setMoveContinuous` de nuevo cuando la dirección haya cambiado lo suficiente como para importar.
{% endhint %}

## Secuencias de tween

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

* `sequence`: Un array con múltiples definiciones de tween, que se llevarán a cabo secuencialmente. El array puede estar vacío, en cuyo 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 la `TweenLoop` enum. Los valores aceptados son:
  * `TL_RESTART`: Cuando la secuencia termina, se reinicia. Si el último estado no coincide con el primero, la entidad salta instantáneamente de uno al otro.
  * `TL_YOYO`: Cuando la secuencia termina, retrocede, haciendo todos los tweens en orden inverso hasta que vuelve a llegar al inicio. Luego comienza una vez más.

### Moverse hacia adelante y hacia atrás

Para hacer que una plataforma se mueva constantemente hacia adelante y hacia atrás entre dos posiciones, deja el `sequence` array vacío, y establece `loop` en `TweenLoop.TL_YOYO`

```ts
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
)

TweenSequence.create(myEntity, { sequence: [], loop: TweenLoop.TL_YOYO })
```

La entidad se moverá de un lado a otro entre el punto de inicio y el punto final, con la misma duración y la misma función easing en ambas direcciones.

### Seguir un recorrido

Para hacer que una entidad siga un recorrido más complejo con múltiples puntos, proporciona una lista de definiciones de tween en el `sequence` de una `TweenSequence` componente.

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

Tween.setMove(myEntity, 
	Vector3.create(6.5, 7, 4), 
	Vector3.create(6.5, 7, 12), 
	4000
)

TweenSequence.create(myEntity, {
	sequence: [
		{
			duration: 2000,
			easingFunction: EasingFunction.EF_LINEAR,
			mode: Tween.Mode.Move({
				start: Vector3.create(6.5, 7, 12),
				end: Vector3.create(6.5, 10.5, 12),
			}),
		},
		{
			duration: 3000,
			easingFunction: EasingFunction.EF_LINEAR,
			mode: Tween.Mode.Move({
				start: Vector3.create(6.5, 10.5, 12),
				end: Vector3.create(6.5, 10.5, 4),
			}),
		},
		{
			duration: 3000,
			easingFunction: EasingFunction.EF_LINEAR,
			mode: Tween.Mode.Move({
				start: Vector3.create(6.5, 10.5, 4),
				end: Vector3.create(6.5, 7, 4),
			}),
		},
	],
	loop: TweenLoop.TL_RESTART,
})
```

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:

* `duración`: Cuántos milisegundos tarda en moverse entre las dos posiciones
* `easingFunction`: Qué función easing usar. Ver [Tweens no lineales](#non-linear-tweens). En este formato, el valor es obligatorio.
* `modo`: El modo del tween, que puede ser `Tween.Mode.Move`, `Tween.Mode.Rotate`, o `Tween.Mode.Scale`.

Y dentro del `modo` campo, necesitas especificar:

* `start`: El valor inicial del tween
* `end`: El valor final del tween

## Al finalizar el tween

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

```ts
engine.addSystem(() => {
	const tweenCompleted = tweenSystem.tweenCompleted(myEntity)
	if (tweenCompleted) {
		//play sound
	}
})
```

## Tweens simultáneos

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

```ts
const myEntity = engine.addEntity()
Transform.create(myEntity, {
	position: Vector3.create(14, 1, 2),
})
MeshRenderer.setBox(myEntity)

Tween.setMoveRotateScale(myEntity, {
	position: { start: Vector3.create(14, 1, 2), end: Vector3.create(14, 3, 2) },
	rotation: { start: Quaternion.fromEulerDegrees(0, 0, 0), end: Quaternion.fromEulerDegrees(0, 180, 90) },
	scale: { start: Vector3.One(), end: Vector3.create(2, 0.5, 2) },
	duration: 2000
})
```

El tween de movimiento toma la siguiente información:

* `entidad`: La entidad a mover
* `params`: Un objeto con los siguientes parámetros
  * `posición`: *(opcional)* Un objeto con un `start` y `end` valor, tanto como `Vector3`.
  * `rotación`: *(opcional)* Un objeto con un `start` y `end` valor, tanto como `Quaternion`.
  * `escala`: *(opcional)* Un objeto con un `start` y `end` valor, tanto como `Vector3`. Al menos uno de `posición`, `rotación` o `escala` debe proporcionarse.
  * `duración`: *(obligatorio)* Cuántos milisegundos tarda en producirse la transición entre los dos conjuntos de valores
  * `easingFunction`: *(opcional)* Qué función easing usar. Ver [Tweens no lineales](#non-linear-tweens)

Una entidad solo puede tener un `Tween` componente, y cada componente tween solo puede realizar una transformación a la vez. A través del `setMoveRotateScale` tipo de tween, 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 anidadas. Por ejemplo, puedes tener una entidad padre invisible que se mueve lateralmente, con una entidad hija visible que rota.

En el siguiente fragmento, una entidad padre rota mientras una entidad hija aumenta de escala.

```ts
const parentEntity = engine.addEntity()
Transform.create(parentEntity, {
	position: Vector3.create(4, 1, 4),
})
MeshRenderer.setBox(parentEntity)
Tween.setRotate(parentEntity, 
	Quaternion.fromEulerDegrees(0, 0, 0), 
	Quaternion.fromEulerDegrees(0, 170, 0), 
	5000
)

const childEntity = engine.addEntity()
Transform.create(childEntity, {
	position: Vector3.create(0, 0, 0),
	parent: parentEntity,
})
MeshRenderer.setBox(childEntity)
Tween.setScale(childEntity, 
	Vector3.create(1, 1, 1), 
	Vector3.create(4, 4, 4), 
	2000
)
```

## Pausar un tween

Para pausar un tween, cambia la `playing` propiedad a false. Para reanudarlo, vuelve a cambiarla a true.

```ts
pointerEventsSystem.onPointerDown(
	{
		entity: button,
		opts: { button: InputAction.IA_POINTER, hoverText: 'pause' },
	},
	() => {
		let tweenData = Tween.getMutable(myEntity)
		tweenData.playing = !tweenData.playing
	}
)
```

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

```ts
pointerEventsSystem.onPointerDown(
	{
		entity: button,
		opts: { button: InputAction.IA_POINTER, hoverText: 'pause' },
	},
	() => {
		if( Tween.has(myEntity)){
			Tween.deleteFrom(myEntity)
		}
		if( TweenSequence.has(myEntity)){
			TweenSequence.deleteFrom(myEntity)
		}
	}
)
```

## Tweens basados en un sistema

En lugar de usar el componente Tween y dejar que el motor gestione la transformación, quizá prefieras realizar esta transición de forma incremental, frame a frame, mediante un sistema [system](/creator/content-creator-es/scenes-sdk7/arquitectura/systems.md) en tu escena. Al mover la entidad 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 complejo, y los jugadores con máquinas menos potentes podrían experimentar el tween como lento, notando cada incremento.

### Mover mediante un sistema

La forma más fácil de mover una entidad es modificar gradualmente el *posición* valor almacenado en el `Transform` componente.

```ts
function SimpleMove() {
	let transform = Transform.getMutable(myEntity)
	transform.position = Vector3.add(
		transform.position,
		Vector3.scale(Vector3.Forward(), 0.05)
	)
}

engine.addSystem(SimpleMove)

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

En este ejemplo estamos moviendo una entidad 0.05 metros por tick del bucle del juego.

`Vector3.Forward()` devuelve un vector que mira hacia adelante y mide 1 metro de largo. En este ejemplo luego estamos reduciendo este vector a 1/20 de su longitud con `Vector3.scale()`. Si nuestra escena tiene 30 frames por segundo, la entidad se mueve a una velocidad de 1.5 metros por segundo.

![](https://1216664193-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-7088aee0c804d1902813dd2d5cd4a999e85a5cf8%2Fmove.gif?alt=media\&token=22d02b05-a757-47f7-a2a8-20239219c328)

### Rotar mediante un sistema

La forma más fácil de rotar una entidad es cambiar gradualmente los valores del componente Transform de forma incremental, y ejecutarlo como parte de la función de un sistema.

```ts
function SimpleRotate() {
	let transform = Transform.getMutable(myEntity)
	transform.rotation = Quaternion.multiply(
		transform.rotation,
		Quaternion.fromAngleAxis(1, Vector3.Up())
	)
}

engine.addSystem(SimpleRotate)

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

Ten en cuenta que, para combinar la rotación actual con cada incremento, estamos usando `Quaternion.multiply`. En la 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 después de realizar primero una rotación y luego la otra.

En este ejemplo, estamos rotando la Entity 1 grado hacia arriba en cada tick del game loop.

{% hint style="info" %}
**💡 Consejo**: Para hacer que una Entity gire siempre para mirar al jugador, puedes añadir un [`Billboard` component](/creator/content-creator-es/scenes-sdk7/fundamentos-del-contenido-3d/entity-positioning.md#face-the-user).
{% endhint %}

![](https://1216664193-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-cadf115f527e7bd6bda804cd4051adedca5f40ef%2Frotate.gif?alt=media\&token=1d4332ad-29a1-4977-a13d-1c4e1777aa71)

### Rotar mediante system alrededor de un punto de pivote

Cuando rotas 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 posición y haz que sea una entidad padre de la entidad que quieres rotar.

Al rotar la entidad padre, todas sus entidades hijas se rotarán usando la posición del padre como punto de pivote. Ten en cuenta que el `posición` de la entidad hija está en referencia a la de la entidad padre.

```ts
function SimpleRotate() {
	let transform = Transform.getMutable(pivotEntity)
	transform.rotation = Quaternion.multiply(
		transform.rotation,
		Quaternion.fromAngleAxis(1, Vector3.Up())
	)
}

engine.addSystem(SimpleRotate)

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

const childEntity = engine.addEntity()
Transform.create(childEntity, {
	position: Vector3.create(1, 0, 0),
	parent: pivotEntity,
})
MeshRenderer.setBox(childEntity)
```

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

![](https://1216664193-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-9d8e4fb2bbc8007ef87c4918cc2b44f3c0cd4a54%2Fpivot-rotate.gif?alt=media\&token=a22ecc83-1398-4936-88ff-fe29799e00b4)

### Ajustar el movimiento al tiempo de retraso

Supongamos que el jugador que visita tu escena tiene dificultades para seguir el ritmo de la tasa de fotogramas. Eso podría hacer que el movimiento se vea entrecortado, ya que no todos los fotogramas están espaciados uniformemente, pero cada uno mueve la Entity en la misma cantidad.

Puedes compensar esta sincronización desigual usando el `dt` parámetro para ajustar la escala del movimiento.

```ts
function SimpleMove(dt: number) {
	let transform = Transform.getMutable(myEntity)
	transform.position = Vector3.add(
		transform.position,
		Vector3.scale(Vector3.Forward(), dt)
	)
}

engine.addSystem(SimpleMove)

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

El ejemplo anterior mantiene el movimiento aproximadamente a la misma velocidad que el ejemplo de movimiento anterior, incluso si la tasa de fotogramas disminuye. Cuando se ejecuta a 30 fotogramas 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 puntos mediante system

Si quieres que una Entity se mueva suavemente entre dos puntos, usa el *lerp* (algoritmo de interpolación lineal). Este algoritmo es muy conocido en el desarrollo de juegos, 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.

```ts
const originVector = Vector3.Zero()
const targetVector = Vector3.Forward()

let newPos = Vector3.lerp(originVector, targetVector, 0.6)
```

El algoritmo de interpolación lineal encuentra un punto intermedio en el recorrido entre ambos vectores 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 escena, recomendamos crear un [componente personalizado](/creator/content-creator-es/scenes-sdk7/arquitectura/custom-components.md) para almacenar la información necesaria. También necesitas definir un system que implemente el movimiento gradual en cada frame.

```ts
// definir componente personalizado
const MoveTransportData = {
	start: Schemas.Vector3,
	end: Schemas.Vector3,
	fraction: Schemas.Float,
	speed: Schemas.Float,
}

export const LerpTransformComponent = engine.defineComponent(
	'LerpTransformComponent',
	MoveTransportData
)

// definir system
function LerpMove(dt: number) {
	let transform = Transform.getMutable(myEntity)
	let lerp = LerpTransformComponent.getMutable(myEntity)
	if (lerp.fraction < 1) {
		lerp.fraction += dt * lerp.speed
		transform.position = Vector3.lerp(lerp.start, lerp.end, lerp.fraction)
	}
}

engine.addSystem(LerpMove)

// crear entidad
const myEntity = engine.addEntity()

Transform.create(myEntity, {
	position: Vector3.create(4, 1, 4),
})

MeshRenderer.setBox(myEntity)

LerpTransformComponent.create(myEntity, {
	start: Vector3.create(4, 1, 4),
	end: Vector3.create(8, 1, 8),
	fraction: 0,
	speed: 1,
})
```

![](https://1216664193-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-821f48b2d4a6afbb451813d7df73aa4196228c0f%2Flerp-move.gif?alt=media\&token=648743af-b3c3-4503-9c9c-c81670b839fe)

### Rotar entre dos ángulos mediante system

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

El `slerp()` function toma tres parámetros:

* El [quaternion](https://en.wikipedia.org/wiki/Quaternion) ángulo para la rotación de origen
* El [quaternion](https://en.wikipedia.org/wiki/Quaternion) ángulo para la rotación de destino
* La cantidad, un valor de 0 a 1 que representa qué fracción de la traslación realizar.

{% hint style="info" %}
**💡 Consejo**: Puedes pasar valores de rotación en [Euler](https://en.wikipedia.org/wiki/Euler_angles) grados (de 0 a 360) usando `Quaternion.fromEulerDegrees()`.
{% endhint %}

```ts
const originRotation = Quaternion.fromEulerDegrees(0, 90, 0)
const targetRotation = Quaternion.fromEulerDegrees(0, 0, 0)

let newRotation = Quaternion.slerp(originRotation, targetRotation, 0.6)
```

Para implementar esto en tu escena, recomendamos almacenar los datos que van en el `Slerp()` function en un [componente personalizado](/creator/content-creator-es/scenes-sdk7/arquitectura/custom-components.md). También necesitas definir un system que implemente la rotación gradual en cada frame.

```ts
// definir componente personalizado
const RotateSlerpData = {
	start: Schemas.Quaternion,
	end: Schemas.Quaternion,
	fraction: Schemas.Float,
	speed: Schemas.Float,
}

export const SlerpData = engine.defineComponent('SlerpData', RotateSlerpData)

// definir system
function SlerpRotate(dt: number) {
	let transform = Transform.getMutable(myEntity)
	let slerpData = SlerpData.getMutable(myEntity)
	if (slerpData.fraction < 1) {
		slerpData.fraction += dt * slerpData.speed
		transform.rotation = Quaternion.slerp(
			slerpData.start,
			slerpData.end,
			slerpData.fraction
		)
	}
}

engine.addSystem(SlerpRotate)

// crear entidad
const myEntity = engine.addEntity()

Transform.create(myEntity, {
	position: Vector3.create(4, 1, 4),
})

MeshRenderer.setBox(myEntity)

SlerpData.create(myEntity, {
	start: Quaternion.fromEulerDegrees(0, 0, 0),
	end: Quaternion.fromEulerDegrees(0, 180, 0),
	fraction: 0,
	speed: 0.3,
})
```

{% hint style="warning" %}
**📔 Nota**: En su lugar, podrías representar la rotación con ángulos de Euler como `Vector3` valores y usar un `Lerp()` función, pero eso implicaría una conversión desde `Vector3` en `Quaternion` en cada frame. Los valores de rotación se almacenan internamente como quaternions en el `Transform` component, por lo que es más eficiente que la escena trabaje con quaternions.
{% endhint %}

![](https://1216664193-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-eb8b524701a7b454c514384eb70c3f48ac0a70b5%2Flerp-rotate.gif?alt=media\&token=cfab88d5-ac0d-4cc1-aa75-c866ec8a8a80)

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

```ts
function SimpleRotate(dt: number) {
	let transform = Transform.getMutable(myEntity)
	transform.rotation = Quaternion.rotateTowards(
		transform.rotation,
		Quaternion.fromEulerDegrees(90, 0, 0),
		dt * 10
	)
	si (
		Quaternion.angle(transform.rotation, Quaternion.fromEulerDegrees(90, 0, 0)) < 0.01
	) {
		console.log('done')
		engine.removeSystem(SimpleRotate)
	}
}

engine.addSystem(SimpleRotate)

const myEntity = engine.addEntity()
Transform.create(myEntity, {
	position: Vector3.create(4, 1, 4),
	rotation: Quaternion.fromEulerDegrees(0, 0, 90),
})

MeshRenderer.setBox(myEntity)
```

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, como el incremento máximo es de `dt * 10` grados, la rotación se llevará a cabo durante un período de unos 9 segundos.

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 estuviera completa.

### Cambiar la escala entre dos tamaños mediante system

Si quieres que una Entity cambie de tamaño suavemente y sin alterar sus proporciones, usa el *lerp* (algoritmo de interpolación lineal) del `Scalar` object.

De lo contrario, si quieres cambiar los ejes en distintas proporciones, usa `Vector3` para representar la escala de origen y la escala de destino, y luego usa el *lerp* función del `Vector3`.

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

* Un número para la escala de origen
* Un número para la escala de destino
* La cantidad, un valor de 0 a 1 que representa qué fracción del escalado realizar.

```ts
const originScale = 1
const targetScale = 10

let newScale = Scalar.lerp(originScale, targetScale, 0.6)
```

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

```ts
// definir componente personalizado
const ScaleTransportData = {
	start: Schemas.Number,
	end: Schemas.Number,
	fraction: Schemas.Float,
	speed: Schemas.Float,
}

export const ScaleTransformComponent = engine.defineComponent(
	'ScaleTransformComponent',
	ScaleTransportData
)

// definir system
function LerpMove(dt: number) {
	let transform = Transform.getMutable(myEntity)
	let lerp = ScaleTransformComponent.getMutable(myEntity)
	if (lerp.fraction < 1) {
		lerp.fraction += dt * lerp.speed
		const newScale = Scalar.lerp(lerp.start, lerp.end, lerp.fraction)
		transform.scale = Vector3.create(newScale, newScale, newScale)
	}
}

engine.addSystem(LerpMove)

// crear entidad
const myEntity = engine.addEntity()

Transform.create(myEntity, {
	position: { x: 4, y: 1, z: 4 },
})

MeshRenderer.setBox(myEntity)

ScaleTransformComponent.create(myEntity, {
	start: 1,
	end: 2,
	fraction: 0,
	speed: 1,
})

Vector3.create(1, 1, 1)
```

![](https://1216664193-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-860402e1bd825057ab2b47d06e95ba6061dc5327%2Flerp-scale.gif?alt=media\&token=094e5b91-4fab-4223-941c-c2107ad96c5d)

### Moverse a velocidades irregulares entre dos puntos 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 por una cantidad dada en cada frame, pero también podríamos usar una función matemática para aumentar el número exponencialmente o mediante otras medidas que te den un ritmo de movimiento diferente.

También podrías usar una función que produzca 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 escena. Un movimiento que acelera a lo largo de una curva o se ralentiza gradualmente puede decir mucho sobre la naturaleza de un objeto o personaje. Incluso podrías aprovechar funciones matemáticas que añadan efectos rebote.

```ts
// definir componente personalizado
const MoveTransportData = {
	start: Schemas.Vector3,
	end: Schemas.Vector3,
	fraction: Schemas.Float,
	speed: Schemas.Float,
}

export const LerpTransformComponent = engine.defineComponent(
	'LerpTransformComponent',
	MoveTransportData
)

// definir system
function LerpMove(dt: number) {
	let transform = Transform.getMutable(myEntity)
	let lerp = LerpTransformComponent.getMutable(myEntity)
	if (lerp.fraction < 1) {
		lerp.fraction += dt * lerp.speed
		const interpolatedValue = interpolate(lerp.fraction)
		transform.position = Vector3.lerp(lerp.start, lerp.end, interpolatedValue)
	}
}

// mapear la fracción de lerp a una curva exponencial
function interpolate(t: number) {
	return t * t
}

engine.addSystem(LerpMove)

// crear entidad
const myEntity = engine.addEntity()

Transform.create(myEntity, {
	position: { x: 4, y: 1, z: 4 },
})

MeshRenderer.setBox(myEntity)

LerpTransformComponent.create(myEntity, {
	start: Vector3.create(4, 1, 4),
	end: Vector3.create(8, 1, 8),
	fraction: 0,
	speed: 1,
})
```

El ejemplo anterior es igual que el ejemplo de lerp lineal que hemos mostrado antes, pero el `fraction` campo se asigna a un valor no lineal en cada tick. Este valor no lineal se usa para calcular la `lerp` función, dando como resultado un movimiento que sigue una curva exponencial.

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

![](https://1216664193-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-91fe24f5e5561834eea21e052ee0036a2987d747%2Flerp-speed-up.gif?alt=media\&token=3ba54949-0936-4dc5-a55d-9feebbbff2ca)

### Seguir una ruta mediante system

Puedes hacer que una Entity recorra en bucle un array de vectores, realizando un movimiento lerp entre cada uno para seguir una ruta más compleja.

```ts
// definir componente personalizado
const PathTransportData = {
	path: Schemas.Array(Schemas.Vector3),
	start: Schemas.Vector3,
	end: Schemas.Vector3,
	fraction: Schemas.Float,
	speed: Schemas.Float,
	pathTargetIndex: Schemas.Int,
}

export const LerpTransformComponent = engine.defineComponent(
	'LerpTransformComponent',
	PathTransportData
)

// definir system
function PathMove(dt: number) {
	let transform = Transform.getMutable(myEntity)
	let lerp = LerpTransformComponent.getMutable(myEntity)
	if (lerp.fraction < 1) {
		lerp.fraction += dt * lerp.speed
		transform.position = Vector3.lerp(lerp.start, lerp.end, lerp.fraction)
	} else {
		lerp.pathTargetIndex += 1
		if (lerp.pathTargetIndex >= lerp.path.length) {
			lerp.pathTargetIndex = 0
		}
		lerp.start = lerp.end
		lerp.end = lerp.path[lerp.pathTargetIndex]
		lerp.fraction = 0
	}
}

engine.addSystem(PathMove)

// crear entidad
const myEntity = engine.addEntity()

Transform.create(myEntity, {
	position: Vector3.create(1, 1, 1),
})

MeshRenderer.setBox(myEntity)

const point1 = Vector3.create(1, 1, 1)
const point2 = Vector3.create(8, 1, 3)
const point3 = Vector3.create(8, 4, 7)
const point4 = Vector3.create(1, 1, 7)

const myPath = [point1, point2, point3, point4]

LerpTransformComponent.create(myEntity, {
	path: myPath,
	start: Vector3.create(4, 1, 4),
	end: Vector3.create(8, 1, 8),
	fraction: 0,
	speed: 1,
	pathTargetIndex: 1,
})
```

El ejemplo anterior define una ruta 3D compuesta 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 `ruta` array, con todos los puntos de nuestra ruta, y un `pathTargetIndex` campo para hacer un seguimiento de qué segmento de la ruta se está usando actualmente.

El system es muy similar al system en el *lerp* ejemplo, pero cuando se completa una acción lerp, establece los `objetivo` y `origin` campos con nuevos valores. Si llegamos al final de la ruta, volvemos al primer valor de la ruta.

![](https://1216664193-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-5ca6c0f3c12c8838c80b848e718d463c4e5fa441%2Flerp-path.gif?alt=media\&token=ab11f133-f26e-40a6-b7a9-740c70c05cd7)

## Tweens de Texture

Para hacer que una Texture se deslice suavemente, usa el `Tween` componente con el `setTextureMove` función.

```ts
Tween.setTextureMove(myEntity, 
	Vector2.create(0, 0), 
	Vector2.create(1, 0), 
	2000
)
```

El tween de Texture toma la siguiente información:

* `entidad`: La Entity de la que se moverá la Texture
* `start`: Un Vector2 para la posición inicial
* `end`: Un Vector2 para la posición final
* `duración`: Cuántos milisegundos tarda en moverse entre las dos posiciones

También está disponible este otro parámetro opcional:

* `movementType`: (opcional), define si el movimiento será en el campo offset o tiling. De forma predeterminada usa offset.
* `easingFunction`: Qué función easing usar. Ver [Tweens no lineales](#non-linear-tweens).

## Movimiento constante de Texture

Para hacer que una Texture se deslice constantemente, usa el `Tween` componente con el `setTextureMoveContinuous` función.

```ts
Tween.setTextureMoveContinuous(myEntity, 
	Vector2.create(0, 1), 
	0.7
)
```

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

* `entidad`: La Entity de la que se moverá la Texture
* `dirección`: Un Vector2 para el movimiento
* `speed`: Cuántas unidades por segundo se moverá la Entity

También está disponible este otro parámetro opcional:

* `movementType`: define si el movimiento será en el campo offset o tiling. De forma predeterminada usa offset.
* `duración`: Cuántos milisegundos mantener el movimiento. Después de ese tiempo, el movimiento se detendrá.

Lee más sobre los tweens de Texture en el [Tweens de Texture](/creator/content-creator-es/scenes-sdk7/fundamentos-del-contenido-3d/materials.md#texture-tweens) sección.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/fundamentos-del-contenido-3d/move-entities.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
