AnimationTree Máquinas de estados
no Godot 4

O guia completo de máquinas de estados, transições, blend trees, OneShot, travel() vs. condições — com exemplos reais de código GDScript.

1. Introdução

O AnimationTree é o sistema do Godot 4 para blending complexo de animações e transições de estado. Se você já tentou gerenciar múltiplas animações com chamadas de AnimationPlayer.play() espalhadas pelo código, sabe como isso rapidamente se torna ingerenciável. O AnimationTree resolve esse problema com um grafo visual de estados e transições.

Apesar de ser incrivelmente poderoso, a documentação oficial do AnimationTree é escassa e muitas vezes deixa os desenvolvedores no escuro. Este guia percorre tudo – da configuração básica aos blend trees avançados – com código GDScript real que você pode copiar direto para o seu projeto.

O que você vai aprender

Máquinas de estados, transições, blend spaces (1D & 2D), OneShot para ataques, travel() vs. condições e um padrão completo de character controller.

2. Pré-requisitos

Antes de configurar o seu AnimationTree, você precisa de:

  • Um node AnimationPlayer com, pelo menos, as animações Idle, Walk, Run e Jump já criadas
  • O AnimationPlayer deve ser um irmão ou filho do node onde você adiciona o AnimationTree (normalmente ambos são filhos do node raiz do seu personagem)
  • Godot 4.x (este guia usa a API do Godot 4 — a API do AnimationTree mudou significativamente em relação ao Godot 3)
Godot 3 vs. Godot 4

No Godot 4, AnimationTree.animation_player foi substituído por AnimationTree.anim_player. O caminho do parâmetro de reprodução também mudou. Se você está migrando do Godot 3, confira o guia de migração oficial.

3. Configuração básica

Configurar um AnimationTree leva quatro passos:

  1. Adicione um node AnimationTree — Adicione-o como filho do seu personagem (ex.: CharacterBody2D ou CharacterBody3D), ao lado do seu AnimationPlayer.
  2. Defina anim_player — No Inspector, aponte a propriedade "Anim Player" para o seu node AnimationPlayer.
  3. Defina tree_root — Clique na propriedade "Tree Root" no Inspector e crie uma nova AnimationNodeStateMachine.
  4. Defina active = true — Marque a caixa "Active" no Inspector ou defina no código.

Sua árvore de cena deve ficar assim:

CharacterBody2D (or CharacterBody3D)
  +-- Sprite2D (or Sprite3D)
  +-- CollisionShape2D
  +-- AnimationPlayer      <-- has Idle, Walk, Run, Jump animations
  +-- AnimationTree         <-- points to AnimationPlayer above
GDScript
# Minimal code setup (usually done via the editor instead):
@onready var anim_tree: AnimationTree = $AnimationTree

func _ready() -> void:
    # If you set these in the Inspector, you don't need this code
    anim_tree.anim_player = ^"../AnimationPlayer"
    anim_tree.tree_root = AnimationNodeStateMachine.new()
    anim_tree.active = true
Editor vs. código

Na prática, você quase sempre configura o AnimationTree no editor. O código acima é mostrado por completude, mas normalmente você só precisa de anim_tree.active = true no seu script (e até isso pode ser definido no editor).

4. Fundamentos da máquina de estados

Uma máquina de estados no AnimationTree funciona com um conceito simples: os estados representam animações e as transições definem as condições para alternar entre elas.

Adicionando estados

Assim que o tree_root do seu AnimationTree for uma AnimationNodeStateMachine, dê duplo clique nele no Inspector para abrir o editor da máquina de estados:

  1. Clique com o botão direito na área do grafo e selecione Add Animation
  2. Escolha uma animação do seu AnimationPlayer (Idle, Walk, Run, Jump, etc.)
  3. Repita para cada estado de animação que você precisar
Estados especiais

Start é o ponto de entrada — a primeira transição sempre começa aqui. End é opcional e sinaliza que a máquina de estados terminou (útil para máquinas de estados aninhadas).

Adicionando transições

Para criar uma transição entre dois estados:

  1. Clique no node do estado de origem
  2. Arraste até o estado de destino para criar uma seta de transição
  3. Clique na seta de transição para configurá-la no Inspector

Propriedades da transição

Propriedade Descrição
advance_mode Auto — dispara quando sua condição é verdadeira. Enabled — sempre disponível para travel(). Disabled — bloqueada.
advance_condition Nome de um parâmetro booleano (ex.: is_moving). Quando verdadeiro, a transição dispara automaticamente.
xfade_time Duração do crossfade em segundos. Blending suave entre animações. Típico: 0.1 – 0.3s.
switch_mode Immediate — troca agora. Sync — alinha a posição de reprodução. AtEnd — aguarda o fim da animação atual.

Uma configuração típica para um personagem de plataforma:

Start --> Idle
Idle  --> Walk   (condition: is_moving)
Walk  --> Idle   (condition: is_idle)
Idle  --> Jump   (condition: is_jumping)
Walk  --> Jump   (condition: is_jumping)
Jump  --> Fall   (condition: is_falling)
Fall  --> Idle   (condition: is_on_floor, switch_mode: Immediate)

5. Controlando a máquina de estados via código

Há duas maneiras principais de conduzir a máquina de estados: definindo parâmetros de condição (transições automáticas) e chamando travel() (transições manuais). Você pode combinar as duas abordagens.

GDScript
extends CharacterBody2D

@onready var anim_tree: AnimationTree = $AnimationTree
@onready var state_machine: AnimationNodeStateMachinePlayback = anim_tree.get("parameters/playback")

func _physics_process(delta: float) -> void:
    # ... movement logic here ...
    move_and_slide()
    _update_animation_parameters()

func _update_animation_parameters() -> void:
    # Approach 1: Set condition parameters — transitions fire automatically
    anim_tree.set("parameters/conditions/is_moving", velocity.length() > 10.0)
    anim_tree.set("parameters/conditions/is_idle", velocity.length() <= 10.0)
    anim_tree.set("parameters/conditions/is_on_floor", is_on_floor())
    anim_tree.set("parameters/conditions/is_jumping", velocity.y < 0 and not is_on_floor())
    anim_tree.set("parameters/conditions/is_falling", velocity.y > 0 and not is_on_floor())

    # Approach 2: Use travel() for direct control
    # if velocity.length() > 10.0:
    #     state_machine.travel("Walk")
    # else:
    #     state_machine.travel("Idle")
Caminhos de parâmetros

Os parâmetros seguem o padrão parameters/conditions/<condition_name> para condições definidas em transições. O nome da condição deve corresponder ao advance_condition que você definiu na transição, no editor.

6. travel() vs. condições

Baseado em condições (recomendado para locomoção)

Defina parâmetros booleanos a cada frame e deixe as transições dispararem automaticamente. Isso é mais declarativo e mantém o seu código limpo. A máquina de estados cuida da lógica de transição, dos crossfades e dos casos extremos por você.

# Declarative: just describe the current state of the world
anim_tree.set("parameters/conditions/is_moving", velocity.length() > 10.0)
anim_tree.set("parameters/conditions/is_on_floor", is_on_floor())

travel() (recomendado para ações pontuais)

travel() solicita uma transição de estado. Ele respeita as regras de transição — se não existir um caminho válido do estado atual até o alvo, a chamada é ignorada. Isso o torna seguro para ser chamado repetidamente. Use-o para gatilhos pontuais como ataques, emotes ou animações de cutscene.

# travel() — requests a transition (respects transition rules)
state_machine.travel("Jump")

# Get current state name
var current: StringName = state_machine.get_current_node()
print(current)  # "Idle", "Walk", etc.

# Check if travel is possible
var is_playing: bool = state_machine.is_playing()
print(is_playing)
Quando usar cada um?

Condições para estados contínuos (idle, walk, run, fall). travel() para estados acionados por eventos (ataque, esquiva, interagir). Muitos projetos usam ambos: condições para a locomoção, travel() para ações de combate.

7. Blend Trees

Os blend trees permitem interpolar suavemente entre várias animações com base em um valor contínuo, em vez de alternar bruscamente entre estados discretos. Isso é ideal para o blending de velocidade de caminhada/corrida e para movimento direcional.

BlendSpace1D

Um blend 1D entre duas ou mais animações ao longo de um único eixo. Uso comum: mesclar Walk e Run com base na velocidade de movimento.

No editor, crie um node BlendSpace1D dentro da sua máquina de estados (ou como tree root autônomo). Adicione pontos de animação:

# BlendSpace1D setup (in editor):
# Point 0.0 = Walk animation
# Point 1.0 = Run animation

# Control from code:
var speed_factor: float = clamp(velocity.length() / max_speed, 0.0, 1.0)
anim_tree.set("parameters/WalkRun/blend_position", speed_factor)

BlendSpace2D

Um blend 2D usando dois eixos. Perfeito para movimento em 8 direções ou jogos top-down em que o personagem pode se mover em qualquer direção.

# BlendSpace2D setup (in editor):
# Place animations at positions:
#   Idle at (0, 0)
#   WalkRight at (1, 0), WalkLeft at (-1, 0)
#   WalkUp at (0, -1), WalkDown at (0, 1)
#   Diagonals at corners

# Control from code:
var input_dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
anim_tree.set("parameters/Movement/blend_position", input_dir)
Modos de blend

O BlendSpace2D suporta vários modos de blend: a triangulação padrão funciona bem na maioria dos casos. Você também pode escolher o modo discreto (encaixa no ponto mais próximo) se quiser animação estilo pixel art sem interpolação.

8. Tipos de node comuns

O AnimationTree suporta vários tipos de node que podem ser combinados para criar comportamentos de animação complexos:

Tipo de node Caso de uso
AnimationNodeStateMachine Máquina de estados com transições. O root node mais comum. Os estados podem ser animações ou máquinas de estados aninhadas.
AnimationNodeBlendSpace1D Blend 1D ao longo de um eixo. Velocidade de caminhada/corrida, ângulo de mira, etc.
AnimationNodeBlendSpace2D Blend 2D usando dois eixos. Movimento direcional, blending de strafe.
AnimationNodeBlendTree Um grafo de operações de blend. Combine vários nodes de blend com lógica personalizada.
AnimationNodeAdd2 Blending aditivo. Sobreponha uma animação a outra (ex.: um offset de mira sobre a caminhada).
AnimationNodeTimeScale Controle de velocidade. Faz uma animação reproduzir mais rápido ou mais devagar em tempo de execução.
AnimationNodeOneShot Sobreposição de animação única. Perfeito para ataques, emotes e reações a golpes.
AnimationNodeTransition Alterna entre várias entradas com crossfades. Alternativa às máquinas de estados para configurações mais simples.

9. Padrão OneShot (ataques, emotes)

O node OneShot é um dos padrões mais úteis do AnimationTree. Ele reproduz uma animação única por cima da sua animação base (como reproduzir um golpe de ataque enquanto caminha) e, em seguida, retorna automaticamente para a animação base.

Configuração no BlendTree

Para usar o OneShot, o root do seu AnimationTree (ou um estado dentro dele) precisa ser um BlendTree:

# BlendTree graph setup:
#
#   [StateMachine] ---> [OneShot "AttackOneShot"] ---> [Output]
#   (base locomotion)      ^
#                          |
#                   [Animation "Attack"]
#                   (shot input)
#
# The StateMachine provides the base (idle/walk/run).
# The Attack animation is connected to the OneShot's "shot" input.

Acionando via código

GDScript
extends CharacterBody2D

@onready var anim_tree: AnimationTree = $AnimationTree

func _input(event: InputEvent) -> void:
    if event.is_action_pressed("attack"):
        _play_attack()

func _play_attack() -> void:
    # Fire the one-shot animation
    anim_tree.set(
        "parameters/AttackOneShot/request",
        AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE
    )

func _process(delta: float) -> void:
    # Check if the one-shot is currently active
    var is_attacking: bool = anim_tree.get("parameters/AttackOneShot/active")
    if is_attacking:
        # Optionally disable movement during attack
        pass

Constantes de request do OneShot

Constante Efeito
ONE_SHOT_REQUEST_FIRE Inicia a reprodução da animação OneShot
ONE_SHOT_REQUEST_ABORT Cancela o OneShot e retorna imediatamente para a base
ONE_SHOT_REQUEST_FADE_OUT Faz o fade out do OneShot (usa a propriedade fadeout_time)
Múltiplos ataques

Para sistemas de combo, use vários nodes OneShot em sequência ou uma máquina de estados aninhada na entrada "shot" do OneShot com os estados Attack1 → Attack2 → Attack3.

10. Exemplo prático: character controller completo

Aqui está um script completo de personagem de plataforma 2D que combina locomoção por máquina de estados com um ataque OneShot. Este é um padrão pronto para produção que você pode adaptar ao seu próprio projeto.

GDScript — player.gd
extends CharacterBody2D

const SPEED := 200.0
const JUMP_VELOCITY := -350.0
const SPRINT_MULTIPLIER := 1.6

@onready var anim_tree: AnimationTree = $AnimationTree
@onready var playback: AnimationNodeStateMachinePlayback = anim_tree.get("parameters/playback")
@onready var sprite: Sprite2D = $Sprite2D

var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")

func _ready() -> void:
    anim_tree.active = true

func _physics_process(delta: float) -> void:
    _apply_gravity(delta)
    _handle_jump()
    _handle_movement()
    move_and_slide()
    _update_animation()

func _apply_gravity(delta: float) -> void:
    if not is_on_floor():
        velocity.y += gravity * delta

func _handle_jump() -> void:
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = JUMP_VELOCITY

func _handle_movement() -> void:
    var direction := Input.get_axis("move_left", "move_right")
    var is_sprinting := Input.is_action_pressed("sprint")
    var current_speed := SPEED * (SPRINT_MULTIPLIER if is_sprinting else 1.0)

    if direction != 0.0:
        velocity.x = direction * current_speed
        sprite.flip_h = direction < 0.0
    else:
        velocity.x = move_toward(velocity.x, 0.0, SPEED)

func _update_animation() -> void:
    # Skip animation updates during attack
    var is_attacking: bool = anim_tree.get("parameters/AttackOneShot/active")
    if is_attacking:
        return

    if not is_on_floor():
        if velocity.y < 0:
            playback.travel("Jump")
        else:
            playback.travel("Fall")
    elif abs(velocity.x) > 10.0:
        if Input.is_action_pressed("sprint"):
            playback.travel("Run")
        else:
            playback.travel("Walk")
    else:
        playback.travel("Idle")

func _input(event: InputEvent) -> void:
    if event.is_action_pressed("attack") and is_on_floor():
        anim_tree.set(
            "parameters/AttackOneShot/request",
            AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE
        )
Estrutura do AnimationTree para este exemplo

Root = BlendTree. Dentro dele: um node StateMachine (com os estados Idle/Walk/Run/Jump/Fall) conectado a um node OneShot ("AttackOneShot"), que por sua vez se conecta ao Output. A animação de ataque se conecta à entrada "shot" do OneShot.

11. Solução de problemas

"A animação não é reproduzida"

Verifique se active = true no AnimationTree e se a propriedade anim_player aponta para um AnimationPlayer válido. Confirme também que o AnimationPlayer realmente contém animações com os nomes que você está referenciando.

"travel() não faz nada"

Certifique-se de que existe um caminho de transição válido entre o estado atual e o estado alvo. travel() falha silenciosamente se nenhum caminho existir. Use state_machine.get_current_node() para depurar em qual estado você realmente está.

"O blend não funciona"

Verifique se o seu valor de blend_position está dentro do intervalo dos pontos do seu blend space. Se os seus pontos estão em 0.0 e 1.0, um valor de 5.0 não funcionará como esperado. Use clamp().

"Warning: AnimationTree is not active"

Defina active = true no editor (caixa de seleção no Inspector) ou na sua função _ready(). O AnimationTree não faz nada enquanto não for ativado.

"A transição baseada em condição não dispara"

Verifique com atenção que: (1) o advance_mode da transição está definido como Auto, (2) o nome do advance_condition corresponde exatamente ao que você definiu no código (diferencia maiúsculas de minúsculas) e (3) você está definindo o parâmetro a cada frame em _physics_process().

"A animação roda, mas o personagem não se move"

O AnimationTree cuida apenas da reprodução de animações. A lógica de movimento (velocity, move_and_slide()) é separada e precisa ser implementada no _physics_process() do seu script.

Quer que a IA construa o seu AnimationTree?

O Godot MCP Pro pode criar máquinas de estados, adicionar estados e transições, configurar blend trees e definir parâmetros — tudo a partir de um único prompt. Diga ao seu assistente de IA qual comportamento de animação você quer e ele constrói o AnimationTree completo para você.

  • create_animation_tree
  • add_state_machine_state
  • add_state_machine_transition
  • set_blend_tree_node
  • set_tree_parameter
  • get_animation_tree_structure
Obter o Godot MCP Pro — $15