> 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-pt/scenes-sdk7/fundamentos-de-conteudo-3d/move-entities.md).

# Mover Entities

Como mover, girar e dimensionar uma entity gradualmente ao longo do tempo, com mudanças incrementais.

Para mover, rodar ou redimensionar uma Entity na sua Scene ao longo de um período de tempo, use o `Tween` componente. O engine executa a transformação desejada de forma suave, mostrando atualizações em cada frame até que a duração especificada termine. Além disso, os `Transform` valores do componente da Entity afetada são atualizados em tempo real caso seja necessário fazer verificações de proximidade no código da scene.

{% hint style="info" %}
**💡 Dica**: No [Scene Editor no Creator Hub](/creator/content-creator-pt/scene-editor/primeiros-passos/about-editor.md), você pode mover entities de forma no-code via **Actions**, veja [Torne qualquer item num smart item](/creator/content-creator-pt/scene-editor/interatividade/make-any-item-smart.md).
{% endhint %}

O componente Tween tem as seguintes funções:

* `setMove`: Mover entre dois pontos
* `setRotate`: Rotacionar entre duas direções
* `setScale`: Escalar entre dois tamanhos
* `setMoveRotateScale`: Fazer a transição simultaneamente nos três parâmetros
* `setMoveContinuous`: Mover continuamente na mesma direção
* `setRotateContinuous`: Rotacionar continuamente na mesma direção
* `setTextureMove`: Deslocar a texture de um material entre duas posições
* `setTextureMoveContinuous`: Deslocar a texture de um material continuamente na mesma direção

## Mover entre dois pontos

Para mover uma Entity entre dois pontos, crie um `Tween` componente com o `setMove` função.

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

O tween de movimento recebe as seguintes informações:

* `entity`: A Entity a mover
* `start`: Um Vector3 para a posição inicial
* `end`: Um Vector3 para a posição final
* `duration`: Quantos milissegundos leva para mover entre as duas posições

Este outro parâmetro opcional também está disponível:

* `easingFunction`: Qual função easing usar. Veja [Tweens não lineares](#non-linear-tweens)

## Rotacionar entre duas direções

Para rotacionar uma Entity entre dois pontos, crie um `Tween` componente com o `setRotate` função.

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

O tween de rotação recebe as seguintes informações:

* `start`: Um Quaternion para a rotação inicial
* `end`: Um Quaternion para a rotação final
* `duration`: Quantos milissegundos leva para mover entre as duas posições

Este outro parâmetro opcional também está disponível:

* `easingFunction`: Qual função easing usar. Veja [Tweens não lineares](#non-linear-tweens)

### Rotacionar com um ponto de pivô

Ao rotacionar uma Entity, a rotação está sempre em referência à coordenada central da Entity. Para rotacionar uma Entity usando outro conjunto de coordenadas como ponto de pivô, crie uma segunda Entity (invisível) com o ponto de pivô como sua posição e torne-a uma parent da Entity que você quer rotacionar.

Ao rotacionar a Entity parent, todas as suas children serão rotacionadas usando a posição da parent como ponto de pivô. Observe que o `position` da child Entity está em referência ao da parent Entity.

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

Observe que, neste exemplo, o system está rotacionando a `pivotEntity` Entity, que é uma parent da `childEntity` entity.

## Escalar entre dois tamanhos

Para alterar a escala de uma Entity entre dois tamanhos, crie um `Tween` componente com o `setScale` função.

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

```

O tween de escala recebe as seguintes informações:

* `start`: Um Vector3 para o tamanho inicial
* `end`: Um Vector3 para o tamanho final
* `duration`: Quantos milissegundos leva para mover entre as duas posições

Este outro parâmetro opcional também está disponível:

* `easingFunction`: Qual função easing usar. Veja [Tweens não lineares](#non-linear-tweens)

## Mover a partir da posição atual

Enquanto um tween está ativo, o engine atualiza os `Transform` valores do componente da Entity em tempo real. Isso significa que você pode ler a posição atual da Entity a partir do seu `Transform` componente a qualquer momento, e usar esse valor como o `start` de um novo tween. A Entity então se move de onde estiver naquele momento até o alvo, não importa como ela chegou lá.

```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" %}
**📔 Observação**: Sempre passe um `start` valor explícito. Se o `start` parâmetro ficar sem valor, ele é tratado como *(0, 0, 0)*, então a Entity é teleportada para a origem da scene antes de se mover. Da mesma forma, se você passar um `start` fixo que não corresponda à posição atual da Entity, a Entity se teleporta visivelmente para essa posição antes de se mover. Leia a posição atual a partir do `Transform` componente da Entity, como nos exemplos desta seção, sempre que quiser que o movimento comece de onde a Entity está no momento.
{% endhint %}

### Redirecionar enquanto se desloca

Chamar `setMove` (ou qualquer uma das outras funções tween) em uma Entity que já tenha um tween em execução substitui o tween em execução pelo novo. Como o `start` é lido da posição ao vivo da Entity, isso redireciona a Entity suavemente no meio do trajeto: muda a direção a partir de onde ela estiver naquele momento, sem saltos.

O exemplo abaixo move uma Entity até o pad que o player clicar. Se o player clicar em outro pad enquanto a Entity ainda estiver se deslocando, a Entity muda de direção suavemente em direção ao novo alvo.

```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 até aqui' },
	},
	() => moveTo(Vector3.create(2, 1, 2))
)

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

Para executar lógica quando a Entity chegar ao destino, veja [On tween finished](#on-tween-finished).

{% hint style="warning" %}
**📔 Observação**: Redirecione dessa forma apenas em resposta a eventos ocasionais, como um clique ou ao alcançar um waypoint. Se o alvo mudar constantemente, por exemplo uma Entity que segue o player, não crie um novo tween a cada frame: a Entity vai travar visivelmente. Veja [Seguir um alvo em movimento](#follow-a-moving-target).
{% endhint %}

## Tweens não lineares

Os tweens podem seguir diferentes **Funções easing** que afetam a taxa de mudança ao longo do tempo. Uma **linear** função, significa que a velocidade da mudança é constante do início ao fim. Há muitas opções para escolher, que desenham curvas de formas diferentes dependendo se o início e/ou o fim começam devagar, e de quanto. Um **easeinexpo** curve começa devagar e termina rápido, aumentando a velocidade exponencialmente; por outro lado, uma **easeoutexpo** curve começa rápido e termina devagar.

{% hint style="info" %}
**💡 Dica**: Experimente diferentes curvas de movimento. As diferenças costumam ser sutis, mas interpretamos subconscientemente informações sobre como as coisas se movem, como peso, fricção ou até personalidade.
{% endhint %}

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

```

O `easingFunction` parâmetro opcional recebe seu valor do `EasingFunction` enum, que oferece as seguintes opções:

* `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`

## Rotação constante

Para fazer uma Entity rotacionar constantemente, use o `Tween` componente com o `setRotateContinuous` função.

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

O tween de rotação contínua recebe as seguintes informações:

* `entity`: A Entity a rotacionar
* `direção`: Um Quaternion que determina o eixo ao redor do qual rotacionar. Apenas o eixo dessa rotação importa, o tamanho do seu ângulo é ignorado. Por exemplo, `Quaternion.fromEulerDegrees(0, -1, 0)` e `Quaternion.fromEulerDegrees(0, -90, 0)` se comportam da mesma forma, ambos rotacionando ao redor do *y* eixo em uma direção negativa.
* `speed`: Quantos graus por segundo a Entity vai rotacionar. Um valor negativo rotaciona na direção oposta.

Este outro parâmetro opcional também está disponível:

* `duration`: Quantos milissegundos manter a rotação. Depois desse tempo, a rotação para.

## Movimento constante

Para fazer uma Entity se mover constantemente na mesma direção, use o `Tween` componente com o `setMoveContinuous` função.

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

O tween de movimento contínuo recebe as seguintes informações:

* `entity`: A Entity a mover
* `direção`: Um Vector3 para o movimento
* `speed`: Quantos metros por segundo a Entity vai se mover

Este outro parâmetro opcional também está disponível:

* `duration`: Quantos milissegundos manter o movimento. Depois desse tempo, o movimento para.

O tween de movimento contínuo recebe as seguintes informações:

### Seguir um alvo em movimento

`setMoveContinuous` também é a ferramenta certa quando o destino continua mudando, por exemplo uma Entity que segue o player. É tentador, em vez disso, criar um novo `setMove` tween a cada frame, mirando a posição mais recente do player, mas isso produz uma oscilação visível.

O motivo é que a posição que você lê do `Transform` componente de uma Entity com tween é a posição que o engine reportou por último de volta para a scene, então ela fica alguns frames atrás de onde a Entity realmente está. Quando você passa esse valor como o `start` de um novo tween, o engine o aplica imediatamente, e a Entity volta para onde estava alguns frames atrás. Uma dessas correções é imperceptível, mas repeti-la muitas vezes por segundo não é.

`setMoveContinuous` evita o problema completamente, porque você fornece uma direção e uma velocidade em vez de um ponto inicial. O engine continua usando a posição real da Entity, então substituir o tween para mudar a direção nunca faz a Entity saltar.

```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) {
		// Perto o suficiente: um tween contínuo não tem destino, então você o para manualmente
		if (Tween.has(myEntity)) {
			Tween.deleteFrom(myEntity)
		}
		return
	}

	const direction = Vector3.subtract(playerPosition, myPosition)
	direction.y = 0 // fique no chão, mesmo que o player pule

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

{% hint style="warning" %}
**📔 Observação**: Um tween contínuo nunca termina por conta própria, então a Entity continua se movendo até que você remova o `Tween` componente com `Tween.deleteFrom()`, ou até que o `duration` opcional acabe. Observe também que reorientar a cada frame envia uma atualização para o engine a cada frame. Para evitar isso, chame `setMoveContinuous` novamente apenas quando a direção tiver mudado o suficiente para fazer diferença.
{% endhint %}

## Sequências de tweens

Para fazer uma Entity executar uma série de tweens em sequência, use o `TweenSequence` componente. Este componente requer dois campos:

* `sequence`: Um array com várias definições de tween, que serão executadas sequencialmente. O array pode estar vazio, caso em que apenas o tween atual será reproduzido.
* `loop` *(opcional)*: Se não for fornecido, a sequência é reproduzida apenas uma vez. Se o campo estiver presente, o valor deve ser um valor do `TweenLoop` enum. Os valores aceitos são:
  * `TL_RESTART`: Quando a sequência termina, ela recomeça. Se o último estado não corresponder ao primeiro, a Entity salta instantaneamente de um para o outro.
  * `TL_YOYO`: Quando a sequência termina, ela volta, fazendo todos os tweens em ordem inversa até chegar novamente ao início. Depois, começa mais uma vez.

### Mover de um lado para o outro

Para fazer uma plataforma se mover continuamente de um lado para o outro entre duas posições, deixe o `sequence` array vazio e defina `loop` como `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 })
```

A Entity vai se mover de um lado para o outro entre o ponto inicial e o ponto final, com a mesma duração e a mesma função easing em ambas as direções.

### Seguir um caminho

Para fazer uma Entity seguir um caminho mais complexo com vários pontos, forneça uma lista de definições de tween no `sequence` de uma `TweenSequence` component.

```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,
})
```

Observe que, ao definir um tween dentro de um TweenSequence, você precisa usar o formato mais detalhado de `Tween.Mode.Move`, ou `Tween.Mode.Rotate`, ou `Tween.Mode.Scale` para definir o tween. Nesse formato mais detalhado, você precisa especificar:

* `duration`: Quantos milissegundos leva para mover entre as duas posições
* `easingFunction`: Qual função easing usar. Veja [Tweens não lineares](#non-linear-tweens). Neste formato, o valor é obrigatório.
* `mode`: O modo do tween, que pode ser `Tween.Mode.Move`, `Tween.Mode.Rotate`, ou `Tween.Mode.Scale`.

E dentro do `mode` campo, você precisa especificar:

* `start`: O valor inicial do tween
* `end`: O valor final do tween

## On tween finished

Use `tweenSystem.tweenCompleted` para detectar quando um tween terminou. Isso pode ser útil para executar ações quando um tween acaba, por exemplo para abrir a porta de um elevador.

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

## Tweens simultâneos

Para mover, rotacionar e escalar uma Entity entre um estado inicial e um estado final, crie uma `Tween` componente com o `setMoveRotateScale` função. Essa função também pode ser usada em qualquer combinação desses três 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
})
```

O tween de movimento recebe as seguintes informações:

* `entity`: A Entity a mover
* `params`: Um objeto com os seguintes parâmetros
  * `position`: *(opcional)* Um objeto com um `start` e `end` valor, tanto como `Vector3`.
  * `rotation`: *(opcional)* Um objeto com um `start` e `end` valor, tanto como `Quaternion`.
  * `scale`: *(opcional)* Um objeto com um `start` e `end` valor, tanto como `Vector3`. Pelo menos um de `position`, `rotation` ou `scale` deve ser fornecido.
  * `duration`: *(obrigatório)* Quantos milissegundos leva para fazer a transição entre os dois conjuntos de valores
  * `easingFunction`: *(opcional)* Qual função easing usar. Veja [Tweens não lineares](#non-linear-tweens)

Uma Entity só pode ter um `Tween` componente, e cada componente tween só pode executar uma transformação por vez. Através do `setMoveRotateScale` tipo de tween, você pode fazer uma Entity se mover lateralmente e também rotacionar ao mesmo tempo, mas ambos esses movimentos seguirão a mesma linha do tempo. Se precisar que as transições sejam independentes entre si, como alternativa você pode usar entities parented. Por exemplo, você pode ter uma Entity parent invisível que se move lateralmente, com um child visível que rotaciona.

No trecho a seguir, uma Entity parent rotaciona enquanto um child 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 um tween

Para pausar um tween, altere a `playing` propriedade para false. Para retomá-lo, altere-a de volta para true.

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

Para encerrar um tween que não precisa continuar, delete o `Tween` componente da Entity. Se a Entity também estiver usando um `TweenSequence` componente, delete esse também.

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

## Tweens baseados em um system

Em vez de usar o componente Tween e deixar o engine lidar com a transformação, você pode preferir fazer essa transição de forma incremental, frame a frame, por meio de um [system](/creator/content-creator-pt/scenes-sdk7/arquitetura/systems.md) na sua scene. Movendo a Entity uma pequena quantidade a cada vez que a função é executada.

Por um lado, isso lhe dá mais controle para recalcular movimentos a cada frame. Por outro lado, o código é mais complicado, e players com máquinas menos performáticas podem perceber o tween como lento, notando cada incremento.

### Mover via system

A forma mais fácil de mover uma Entity é modificar gradualmente o *position* valor armazenado no `Transform` component.

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

Neste exemplo, estamos movendo uma Entity em 0.05 metros por tick do game loop.

`Vector3.Forward()` retorna um vector que aponta para frente e mede 1 metro de comprimento. Neste exemplo, então reduzimos esse vector para 1/20 do seu comprimento com `Vector3.scale()`. Se a nossa scene tiver 30 frames por segundo, a Entity estará se movendo a 1.5 metros por segundo de velocidade.

![](https://2402076176-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)

### Rotacionar via system

A forma mais fácil de rotacionar uma Entity é alterar gradualmente os valores no componente Transform de forma incremental, e executar isso como parte da função de um system de um system.

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

Observe que, para combinar a rotação atual com cada incremento, estamos usando `Quaternion.multiply`. Na matemática de quaternion, você combina duas rotações multiplicando-as, NÃO somando-as. A rotação resultante de multiplicar um quaternion por outro será a rotação final equivalente após primeiro realizar uma rotação e depois a outra.

Neste exemplo, estamos girando a entity em 1 grau para cima a cada tick do game loop.

{% hint style="info" %}
**💡 Dica**: Para fazer com que uma entity esteja sempre voltada para o player, você pode adicionar um [`Billboard` component](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/entity-positioning.md#face-the-user).
{% endhint %}

![](https://2402076176-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)

### Girar via system em torno de um ponto pivô

Ao rotacionar uma Entity, a rotação está sempre em referência à coordenada central da Entity. Para rotacionar uma Entity usando outro conjunto de coordenadas como ponto de pivô, crie uma segunda Entity (invisível) com o ponto de pivô como sua posição e torne-a uma parent da Entity que você quer rotacionar.

Ao rotacionar a Entity parent, todas as suas children serão rotacionadas usando a posição da parent como ponto de pivô. Observe que o `position` da child Entity está em referência ao da parent Entity.

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

Observe que, neste exemplo, o system está rotacionando a `pivotEntity` Entity, que é uma parent da `childEntity` entity.

![](https://2402076176-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 o movimento para o tempo de atraso

Suponha que o player que visita sua scene esteja com dificuldade de acompanhar o ritmo da taxa de quadros. Isso pode resultar em o movimento parecer truncado, já que nem todos os frames são cronometrados igualmente, mas cada um move a entity na mesma quantidade.

Você pode compensar esse tempo irregular usando o `dt` parâmetro para ajustar a escala do movimento.

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

O exemplo acima mantém o movimento aproximadamente na mesma velocidade que o exemplo de movimento acima, mesmo que a taxa de quadros caia. Ao executar a 30 quadros por segundo, o valor de `dt` é 1/30.

Você também pode suavizar rotações da mesma forma multiplicando a quantidade de rotação por `dt`.

### Mover entre dois pontos via system

Se você quiser que uma entity se mova suavemente entre dois pontos, use o *lerp* (algoritmo de interpolação linear). Esse algoritmo é muito conhecido no desenvolvimento de jogos, pois é realmente útil.

O `lerp()` função recebe três parâmetros:

* O vetor para a posição de origem
* O vetor para a posição de destino
* A quantidade, um valor de 0 a 1 que representa qual fração da translação deve ser feita.

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

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

O algoritmo de interpolação linear encontra um ponto intermediário no caminho entre ambos os vetores que corresponde à quantidade fornecida.

Por exemplo, se o vetor de origem for *(0, 0, 0)* e o vetor de destino for *(10, 0, 10)*:

* Usar uma quantidade de 0 retornaria *(0, 0, 0)*
* Usar uma quantidade de 0.3 retornaria *(3, 0, 3)*
* Usar uma quantidade de 1 retornaria *(10, 0, 10)*

Para implementar isso `lerp()` em sua scene, recomendamos criar um [componente personalizado](/creator/content-creator-pt/scenes-sdk7/arquitetura/custom-components.md) para armazenar as informações necessárias. Você também precisa definir um system que implemente o movimento gradual em cada frame.

```ts
// definir custom component
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)

// criar entity
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://2402076176-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)

### Girar entre dois ângulos via system

Para girar suavemente entre dois ângulos, use o *slerp* (*esférica* (algoritmo de interpolação linear). Esse algoritmo é muito semelhante a um *lerp*, mas ele lida com rotações de quaternion.

O `slerp()` função recebe três parâmetros:

* O [quaternion](https://en.wikipedia.org/wiki/Quaternion) ângulo para a rotação de origem
* O [quaternion](https://en.wikipedia.org/wiki/Quaternion) ângulo para a rotação de destino
* A quantidade, um valor de 0 a 1 que representa qual fração da translação deve ser feita.

{% hint style="info" %}
**💡 Dica**: Você pode passar valores de rotação em [euler](https://en.wikipedia.org/wiki/Euler_angles) graus (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 isso em sua scene, recomendamos armazenar os dados que entram na `Slerp()` função em um [componente personalizado](/creator/content-creator-pt/scenes-sdk7/arquitetura/custom-components.md). Você também precisa definir um system que implemente a rotação gradual em cada frame.

```ts
// definir custom component
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)

// criar entity
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" %}
**📔 Observação**: Em vez disso, você poderia representar a rotação com valores de ângulos de euler como `Vector3` valores e usar uma `Lerp()` função, mas isso implicaria uma conversão de `Vector3` como `Quaternion` em cada frame. Os valores de rotação são armazenados internamente como quaternions no `Transform` componente, então é mais eficiente para a scene trabalhar com quaternions.
{% endhint %}

![](https://2402076176-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)

Uma abordagem mais simples, porém menos eficiente, para isso aproveita a `Quaternion.rotateTowards` função e evita o uso de quaisquer custom components.

```ts
function SimpleRotate(dt: number) {
	let transform = Transform.getMutable(myEntity)
	transform.rotation = Quaternion.rotateTowards(
		transform.rotation,
		Quaternion.fromEulerDegrees(90, 0, 0),
		dt * 10
	)
	if (
		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)
```

No exemplo acima `Quaternion.rotateTowards` recebe três argumentos: a rotação inicial, a rotação final desejada e o incremento máximo por frame. Neste caso, como o incremento máximo é de `dt * 10` graus, a rotação será realizada ao longo de um período de cerca de 9 segundos.

Observe que o system também verifica se a rotação está concluída e, se estiver, remove o system do engine. Caso contrário, o system continuaria fazendo cálculos em todos os frames, mesmo depois de a rotação estar concluída.

### Alterar a escala entre dois tamanhos via system

Se você quiser que uma entity mude de tamanho suavemente e sem alterar suas proporções, use o *lerp* (algoritmo de interpolação linear) do `Scalar` objeto.

Caso contrário, se você quiser alterar o eixo em proporções diferentes, use `Vector3` para representar a escala de origem e a escala de destino, e então use o *lerp* função do `Vector3`.

O `lerp()` função do `Scalar` objeto recebe três parâmetros:

* Um número para a escala de origem
* Um número para a escala de destino
* A quantidade, um valor de 0 a 1 que representa qual fração do escalonamento deve ser feita.

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

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

Para implementar este lerp em sua scene, recomendamos criar um custom component para armazenar as informações necessárias. Você também precisa definir um system que implemente o escalonamento gradual em cada frame.

```ts
// definir custom component
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)

// criar entity
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://2402076176-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)

### Mover em velocidades irregulares entre dois pontos via system

Ao usar o método lerp, você pode tornar a velocidade do movimento não linear. No exemplo anterior, incrementamos a quantidade de lerp por uma determinada quantidade em cada frame, mas também poderíamos usar uma função matemática para aumentar o número exponencialmente ou de outras maneiras que lhe deem um ritmo de movimento diferente.

Você também poderia usar uma função que fornece resultados recorrentes, como uma função seno, para descrever um movimento que vai e vem.

Muitas vezes, essas transições não lineares podem dar muita vida a uma scene. Um movimento que acelera ao longo de uma curva ou desacelera gradualmente pode dizer muito sobre a natureza de um objeto ou personagem. Você poderia até aproveitar funções matemáticas que adicionam efeitos de quique.

```ts
// definir custom component
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 a fraction do lerp para uma curva exponencial
function interpolate(t: number) {
	return t * t
}

engine.addSystem(LerpMove)

// criar entity
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,
})
```

O exemplo acima é igual ao exemplo de lerp linear que mostramos antes, mas o `fraction` campo mapeado para um valor não linear a cada tick. Esse valor não linear é usado para calcular a `lerp` função, resultando em um movimento que segue uma curva exponencial.

Você também pode mapear uma transição na rotação ou na escala da mesma maneira mostrada acima, mapeando uma transição linear para uma curva.

![](https://2402076176-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 um caminho via system

Você pode fazer com que uma entity percorra um array de vetores, realizando um movimento de lerp entre cada um para seguir um caminho mais complexo.

```ts
// definir custom component
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)

// criar entity
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,
})
```

O exemplo acima define um caminho 3D composto por quatro vetores 3D. O `PathTransportData` custom component contém os mesmos dados usados pelo custom component no *lerp* exemplo acima, mas adiciona um `path` array, com todos os pontos do nosso caminho, e um `pathTargetIndex` campo para acompanhar qual segmento do caminho está atualmente em uso.

O system é muito semelhante ao system no *lerp* exemplo, mas quando uma ação de lerp é concluída, ele define os `alvo` e `origin` campos com novos valores. Se alcançarmos o fim do path, retornamos ao primeiro valor do path.

![](https://2402076176-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)

## Texture tweens

Para fazer uma texture deslizar suavemente, use o `Tween` componente com o `setTextureMove` função.

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

O texture tween recebe as seguintes informações:

* `entity`: A entity para a qual a texture será movida
* `start`: Um Vector2 para a posição inicial
* `end`: Um Vector2 para a posição final
* `duration`: Quantos milissegundos leva para mover entre as duas posições

Este outro parâmetro opcional também está disponível:

* `movementType`: (opcional), define se o movimento será no campo offset ou no tiling. Por padrão, usa offset.
* `easingFunction`: Qual função easing usar. Veja [Tweens não lineares](#non-linear-tweens).

## Movimento constante de texture

Para fazer uma texture deslizar continuamente, use o `Tween` componente com o `setTextureMoveContinuous` função.

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

O texture continuous tween recebe as seguintes informações:

* `entity`: A entity para a qual a texture será movida
* `direção`: Um Vector2 para o movimento
* `speed`: Quantas unidades por segundo a entity se moverá

Este outro parâmetro opcional também está disponível:

* `movementType`: define se o movimento será no campo offset ou no tiling. Por padrão, usa offset.
* `duration`: Quantos milissegundos manter o movimento. Depois desse tempo, o movimento para.

Leia mais sobre texture tweens no [Texture Tweens](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/materials.md#texture-tweens) seção.


---

# 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-pt/scenes-sdk7/fundamentos-de-conteudo-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.
