> 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/3d-model-animations.md).

# Animações de Modelos 3D

Como animar modelos 3D na sua scene

Modelos 3D em *.glTF* e *.glb* podem incluir quantas animações você quiser neles. As animações dizem ao mesh como se mover, especificando uma série de *keyframes* que são distribuídos ao longo do tempo; então o mesh faz a transição de uma pose para a outra para simular movimento contínuo.

A maioria das animações de modelos 3D são [*skeletal animations*](https://en.wikipedia.org/wiki/Skeletal_animation). Essas animações simplificam a geometria complexa do modelo em uma "figura de palitos", vinculando cada vertex do mesh ao bone mais próximo no *bone* no *skeleton*. Os modeladores ajustam o skeleton em diferentes poses, e o mesh se estica e se dobra para acompanhar esses movimentos.

Como alternativa, *vertex animations* animam um modelo sem a necessidade de um skeleton. Essas animações especificam diretamente a posição de cada vertex no modelo. Decentraland também oferece suporte a essas animações.

Consulte [Animations](https://github.com/decentraland/docs/blob/main/creator/3d-modeling/animations.md) para ver detalhes sobre como criar animações para um modelo 3D. Leia [Shape components](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/shape-components.md) para instruções sobre como importar um modelo 3D para uma scene.

{% hint style="info" %}
**💡 Dica**: As animações geralmente são melhores para mover algo no lugar, e não para alterar a posição de uma entity. Por exemplo, você pode definir uma animação para mover os pés de um personagem sem sair do lugar, mas para alterar a localização da entity é melhor usar o component Transform. Consulte [Positioning entities](/creator/content-creator-pt/scenes-sdk7/fundamentos-de-conteudo-3d/move-entities.md) para mais detalhes.
{% endhint %}

## Verifique se um modelo 3D tem animações

Nem todos os arquivos glTF incluem animações. Para ver se há alguma disponível, você pode fazer o seguinte: *glTF* files incluem animações. Para ver se há alguma disponível, você pode fazer o seguinte:

* Se estiver usando [VS Code](https://code.visualstudio.com/)(recomendado), instale a *GLTF Tools* extensão e visualize o conteúdo de um arquivo glTF ali.
* Abra o [Babylon Sandbox](https://sandbox.babylonjs.com/) site e arraste o arquivo glTF (e quaisquer *.jpg* ou *.bin* dependências) para o navegador.
* Abra o *.glTF* arquivo com um editor de texto e role até encontrar *"animations":*.

{% hint style="info" %}
**💡 Dica**: Em *skeletal* animations, um nome de animação geralmente é composto pelo nome de sua armature, um sublinhado e o nome da animação. Por exemplo `myArmature_animation1`.
{% endhint %}

## Reprodução automática

Se um modelo 3D incluir alguma animação, o comportamento padrão é que a primeira delas sempre seja reproduzida em loop.

Para evitar esse comportamento, adicione um `Animator` component à entity que tem o modelo e, então, trate a reprodução das animações explicitamente. Se um `Animator` component estiver presente na entity, todas as animações assumem por padrão o estado `playing: false` e precisam ser reproduzidas manualmente.

{% hint style="info" %}
**💡 Dica**: No [Scene Editor](/creator/content-creator-pt/scene-editor/primeiros-passos/about-editor.md), você pode adicionar um **Animator** component visualmente. Consulte [Add Components](/creator/content-creator-pt/scene-editor/construir/components.md#add-components). Você também pode controlar animações de forma no-code via **Actions**, veja [Make any item smart](/creator/content-creator-pt/scene-editor/interatividade/make-any-item-smart.md).
{% endhint %}

## Lidar com animações explicitamente

Um `Animator` component é usado para acessar todas as animações da entity e pode ser usado para dizer explicitamente à entity para reproduzir ou parar uma animação. O `Animator` component inclui um array de `states`, essa lista deve incluir um objeto para cada uma das animações que o modelo 3D pode executar. Um único `Animator` component pode incluir quantos states forem necessários.

```ts
// Criar entity
const shark = engine.addEntity()

// Adicionar um modelo 3D a ela
GltfContainer.create(shark, {
	src: 'models/shark.glb',
})

Animator.create(shark, {
	states: [
		{
			clip: 'swim',
			playing: true,
			loop: true,
		},
	],
})
```

Cada `state` object mantém o controle de se uma animação está sendo reproduzida no momento.

{% hint style="warning" %}
**📔 Nota**: O `Animator` component deve ser importado via

> `import { Animator } from "@dcl/sdk/ecs"`

Consulte [Imports](/creator/content-creator-pt/scenes-sdk7/primeiros-passos/coding-scenes.md#imports) para saber como lidar com isso facilmente.
{% endhint %}

## Obter uma animação

Obtenha um clip do `Animator` pelo nome usando a `.Animator.getClip()` função. Essa função retorna uma versão mutável do object de state da animação.

```ts
const swimAnim = Animator.getClip(sharkEntity, 'swim')
```

`Animator.getClip` requer os seguintes parâmetros:

* `entity`: A entity do `Animator` component que você deseja consultar.
* `clipName`: String para o nome do clip que você deseja obter.

`Animator.getClip` obtém uma versão mutável do state da animação, então você pode modificar livremente os valores do que essa função retorna.

```ts
const swimAnim = Animator.getClip(sharkEntity, 'swim')
swimAnim.loop = false
```

{% hint style="warning" %}
**📔 Nota**: Se você tentar usar `Animator.getClip()` para obter um clip que não está listado no `Animator` component, ela gera um erro. Use `Animator.getClipOrNull()` se preferir obter uma `null` resposta nesse caso, em vez de um erro.
{% endhint %}

## Reproduzir uma animação

O `.playing` campo em um state de animação determina se a animação está sendo reproduzida no momento. Observe que várias animações podem estar sendo reproduzidas em um único modelo 3D ao mesmo tempo.

Use a `Animator.playSingleAnimation()` função em um `AnimationState` object.

```ts
Animator.playSingleAnimation(sharkEntity, 'swim')
```

Se a entity estava reproduzindo outras animações, `Animator.playSingleAnimation` as interrompe.

`Animator.playSingleAnimation` requer os seguintes parâmetros:

* `entity`: A entity do `Animator` component que você deseja afetar.
* `clipName`: String para o nome do clip que você deseja reproduzir.
* `resetCursor`: *(opcional)* Se *true*, ela reproduz a animação do início, mesmo que a animação tenha sido pausada anteriormente. Se *false*, ela continuará reproduzindo a animação de onde foi pausada. Padrão: *true*.

```ts
Animator.playSingleAnimation(sharkEntity, 'swim', false)
```

A tabela a seguir resume como `Animator.playSingleAnimation()` se comporta, usando valores diferentes para a `resetCursor` property:

|                                  | `resetCursor` = *false*             | `resetCursor` = *true* (padrão) |
| -------------------------------- | ----------------------------------- | ------------------------------- |
| **Sendo reproduzida no momento** | Não tem efeito.                     | Reproduz desde o início.        |
| **Pausada**                      | Retoma do último frame reproduzido. | Reproduz desde o início.        |
| **Concluída (sem loop)**         | Reproduz desde o início.            | Reproduz desde o início.        |

## Animações em loop

Por padrão, as animações são reproduzidas em um loop que repete a animação para sempre.

Altere essa configuração definindo a `loop` property no `state` object.

```ts
Animator.create(shark, {
	states: [
		{
			clip: 'bite',
			playing: true,
			loop: false,
		},
	],
})
```

Se `loop` é definido como *false*, a animação é reproduzida apenas uma vez e depois para, permanecendo na postura do último frame.

## Parar uma animação

Para parar todas as animações que uma entity está reproduzindo, use `Animator.stopAllAnimations()`.

```ts
Animator.stopAllAnimations(shark)
```

`Animator.stopAllAnimations` requer os seguintes parâmetros:

* `entity`: A entity do `Animator` component que você deseja afetar.
* `resetCursor`: *(opcional)* Se *true*, ela volta para a postura do primeiro frame da animação. Se *false*, permanece pausada na postura atual. Padrão: *true*.

{% hint style="warning" %}
**📔 Nota**: Ao reproduzir uma animação com `Animator.playSingleAnimation`, essa função lida com a interrupção de todas as outras animações nos bastidores. Nesse caso, você não precisa interromper explicitamente as outras animações.
{% endhint %}

Quando uma animação termina de reproduzir uma animação sem loop, por padrão o modelo 3D permanece na última postura que tinha. A `shouldReset` property controla o que acontece quando uma animação parada é reproduzida novamente: se *true*, a animação é restaurada ao seu state inicial (seu primeiro frame, ou seu último frame se estiver reproduzindo com uma `speed`) sempre que ela muda de parada para reproduzindo. Se *false* (o padrão), ela retoma de onde estava.

```ts
Animator.create(shark, {
	states: [
		{
			clip: 'bite',
			playing: true,
			shouldReset: true,
			loop: true,
		},
	],
})
```

Você também pode usar `Animator.stopAllAnimations()` a qualquer momento para definir explicitamente a postura de volta para o primeiro frame da animação.

{% hint style="warning" %}
**📔 Nota**: Redefinir a postura é uma mudança abrupta. Se você quiser fazer o modelo transitar suavemente para outra postura, reproduza a outra animação e faça a transição entre as duas ajustando gradualmente suas `weight` properties. Consulte [Animation weight](#animation-weight).
{% endhint %}

## Detectar quando uma animação termina

Quando uma animação sem loop termina de ser reproduzida, o engine define o `playing` property novamente para *false*. O código da sua scene pode ler esse valor para saber quando a animação terminou, por exemplo para emendar outra animação logo em seguida.

```ts
let wasPlaying = false

engine.addSystem(() => {
	const animator = Animator.get(shark)
	const biteState = animator.states.find((state) => state.clip === 'bite')
	const isPlaying = biteState?.playing ?? false

	if (wasPlaying && !isPlaying) {
		console.log('bite animation finished')
		// emendar a próxima animação
		Animator.playSingleAnimation(shark, 'swim')
	}

	wasPlaying = isPlaying
})
```

{% hint style="warning" %}
**📔 Nota**: Ao consultar o state da animação a cada frame, sempre leia-o por meio de `Animator.get()` (somente leitura). Não use `Animator.getClip()` ou `Animator.getMutable()` para consulta: isso retorna uma versão mutável do component, que o marca como alterado em cada frame e causa trabalho desnecessário de sincronização.

O `playing` property só é alternado pelo engine quando a animação termina por conta própria. Animações em loop são reproduzidas até serem interrompidas, então nunca alternam a property sozinhas, e animações com `speed` definido como 0 nunca terminam.
{% endhint %}

{% hint style="warning" %}
**📔 Nota**: Este recurso é suportado apenas no cliente Desktop.
{% endhint %}

## Lidar com várias animações

Se um modelo 3D tiver várias animações empacotadas nele, um único `Animator` component pode lidar com todas elas.

```ts
// Criar entity
const shark = engine.addEntity()

// Adicionar um modelo 3D a ela
GltfContainer.create(shark, {
	src: 'models/shark.glb'
})

Animator.create(shark, {
	states:[{
			clip: "swim",
			playing: true,
			loop: true
		}, {
			clip: "bite",
			playing: true,
			loop: true
		}
	]
})
```

No exemplo acima, duas animações são tratadas por objects separados, e depois ambas são atribuídas ao mesmo `state` objects `Animator` component.

Cada bone em uma animação só pode ser afetado por uma animação por vez, a menos que essas animações tenham um `weight` que some um valor de 1 ou menos.

Se uma animação afeta apenas as pernas de um personagem e outra afeta apenas a cabeça do personagem, então elas podem ser reproduzidas ao mesmo tempo sem nenhum problema. Mas se ambas afetam as pernas do personagem, então você deve ou reproduzir apenas uma de cada vez, ou reproduzi-las com valores de `weight` weight menores.

Se, no exemplo acima, a `bite` animação afeta apenas a boca do shark, e a `swim` animação afeta apenas os bones da coluna do shark, então ambas podem ser reproduzidas ao mesmo tempo.

{% hint style="warning" %}
**📔 Nota**: `Animator.playSingleAnimation()` interrompe todas as outras animações que a entity está reproduzindo no momento. Para reproduzir várias animações ao mesmo tempo, modifique o `playing` property nas animation states manualmente.
{% endhint %}

## Velocidade da animação

Altere a velocidade com que uma animação é reproduzida mudando a `speed` property. O valor de speed é 1 por padrão.

```ts
Animator.create(shark, {
	states: [
		{
			clip: 'swim',
			playing: true,
			loop: true,
			speed: 2,
		},
	],
})
```

Defina speed menor que 1 para reproduzi-la mais lentamente, por exemplo 0.5 para reproduzi-la na metade da velocidade. Defina-o maior que 1 para reproduzi-la mais rapidamente, por exemplo 2 para reproduzi-la no dobro da velocidade.

```ts
const swimAnim = Animator.getClip(sharkEntity, 'swim')

swimAnim.speed = 0.5
```

## Animation weight

O `weight` property permite que um único modelo execute várias animações ao mesmo tempo, calculando uma média ponderada de todos os movimentos envolvidos na animação. O valor de `weight` determina quanta importância essa animação receberá na média.

Por padrão, `weight` é igual a *1*. O valor de `weight` não pode ser maior que *1*.

```ts
Animator.create(shark, {
	states: [
		{
			clip: 'swim',
			playing: true,
			loop: true,
			weight: 0.2,
		},
	],
})
```

O `weight` o valor de todas as animações ativas em uma entity deve somar 1 o tempo todo. Se somar menos que 1, a média ponderada usará a posição padrão da armature para a parte restante do cálculo.

Por exemplo, no exemplo de código acima, estamos reproduzindo a *swim* animação, que tem apenas um `weight` de *0.2*. Esse movimento de natação será bem sutil: apenas 20% da intensidade definida pela animação. Os 80% restantes do cálculo pegam valores da postura padrão da armature.

O `weight` property pode ser usada de maneiras interessantes, por exemplo a `weight` property de *swim* poderia ser definida em proporção à velocidade com que o shark está nadando, então você não precisa criar várias animações para natação rápida e lenta.

Você também poderia alterar o `weight` valor gradualmente ao iniciar e parar uma animação para dar a ela uma transição mais natural e evitar saltos da pose padrão para a primeira pose da animação.

{% hint style="warning" %}
**📔 Nota**: O valor de `weight` adicionado de todas as animações que atuam sobre um bone de um modelo 3D não pode ser maior que 1. Se mais de uma animação estiver afetando os mesmos bones ao mesmo tempo, elas precisam ter seus weights definidos para valores que somem menos que 1.
{% endhint %}

```ts
const swimAnim = Animator.getClip(sharkEntity, 'swim')

swimAnim.weight = 0.5
```


---

# 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/3d-model-animations.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.
