Voltar para o Blog
Quest Log

Plataformas Moveis no Godot 4: AnimatableBody2D e Path2D

Cena 2D no Godot mostrando uma plataforma deslizando sobre um caminho com o player em cima

Aprenda a criar plataforma movel godot com AnimatableBody2D, sync_to_physics e Path2D, levando o player junto sem bugs de fisica no Godot 4.

Quase todo jogo de plataforma chega num ponto em que o chao precisa se mexer. Elevadores, plataformas que vao e voltam, esteiras que carregam o jogador para o outro lado de um abismo. Montar uma plataforma movel godot que funciona parece simples ate o player comecar a tremer, deslizar ou atravessar o chao na hora errada. O segredo nao esta em mover o objeto de qualquer jeito, e sim em escolher o no certo e mover ele de um jeito que a fisica entenda.

Plataformas Moveis no Godot 4: AnimatableBody2D e Path2D

Neste tutorial voce vai entender por que o AnimatableBody2D existe, o que o sync_to_physics faz por baixo dos panos, como mover a plataforma com Tween ou com Path2D/PathFollow2D, e como fazer o player ser carregado junto sem gambiarra. Tudo em Godot 4.x, com codigo que compila.

Por que nao usar um StaticBody2D ou mover na unha

A primeira ideia de quem esta comecando e pegar um StaticBody2D, colocar um collision e mexer na position dentro do _process. Funciona visualmente, mas a fisica nao concorda. Um StaticBody2D foi feito para nao se mexer. Quando voce muda a posicao dele direto, o motor de fisica nao calcula a velocidade do corpo, entao o CharacterBody2D em cima dele nao recebe nenhuma informacao de movimento. Resultado: o player fica parado enquanto o chao escorrega embaixo dele, ou trava de forma estranha.

O RigidBody2D tambem nao serve aqui. Ele responde a forcas e gravidade, e voce nao quer que sua plataforma caia ou seja empurrada quando o player pula em cima. Voce quer controle total do caminho, mas com a fisica ciente do movimento.

E ai que entra o AnimatableBody2D. Ele e um corpo cinematico pensado exatamente para isso: voce controla a posicao dele (por codigo, animacao ou tween), e o motor calcula a velocidade sintetica para que outros corpos reajam de forma correta.

AnimatableBody2D e o sync_to_physics

Crie a cena da plataforma assim:

# Estrutura da cena:
# Plataforma (AnimatableBody2D)
#  ├── CollisionShape2D
#  └── Sprite2D (ou um Polygon2D, AnimatedSprite2D, etc.)

No Inspector do AnimatableBody2D voce vai achar a propriedade Sync To Physics. Ela vem ligada por padrao no Godot 4 e e justamente o que faz a plataforma funcionar bem com um player em cima.

Quando sync_to_physics esta true, o motor faz duas coisas importantes:

  1. Move o corpo durante o passo de fisica (e nao no meio do frame de render), o que evita tremor.
  2. Calcula a velocidade do corpo a partir da mudanca de posicao, e essa velocidade e o que permite empurrar e carregar outros corpos.

A regra de ouro: com sync_to_physics ligado, mova o AnimatableBody2D dentro do _physics_process, nunca no _process. Se voce misturar render e fisica, o calculo de velocidade fica errado e o player volta a tremer.

extends AnimatableBody2D

@export var velocidade: float = 80.0
@export var distancia: float = 200.0

var _origem: Vector2
var _direcao: int = 1

func _ready() -> void:
    _origem = position

func _physics_process(delta: float) -> void:
    position.x += velocidade * _direcao * delta
    if absf(position.x - _origem.x) >= distancia:
        _direcao *= -1

Esse e o caso mais simples: uma plataforma de ida e volta no eixo X. Ela anda distancia pixels, inverte a _direcao e volta. Como estamos no _physics_process e o sync_to_physics esta ligado, o player em cima e levado junto sem voce escrever nada para isso.

Levando o player junto sem escorregar

Aqui vale entender o "por que". O CharacterBody2D do player nao recebe gravidade da plataforma; ele apenas detecta que esta apoiado num corpo que tem velocidade. Para o player ser carregado de forma limpa, duas coisas precisam estar certas no script do personagem.

Primeiro, use move_and_slide(). Ele ja considera a velocidade da plataforma por baixo (a chamada get_platform_velocity() existe justamente para isso). Segundo, mantenha floor_snap_length num valor razoavel para o player nao "pular" da plataforma quando ela desce.

extends CharacterBody2D

const VELOCIDADE := 130.0
const FORCA_PULO := -330.0

func _physics_process(delta: float) -> void:
    if not is_on_floor():
        velocity += get_gravity() * delta

    if Input.is_action_just_pressed("pular") and is_on_floor():
        velocity.y = FORCA_PULO

    var direcao := Input.get_axis("esquerda", "direita")
    velocity.x = direcao * VELOCIDADE

    move_and_slide()

Repare que nao ha nenhuma mencao a plataforma neste script. O move_and_slide() cuida disso quando o chao e um AnimatableBody2D com sync_to_physics. Se voce ja seguiu o tutorial de movimento de personagem em plataforma 2D, esse codigo vai parecer familiar, porque a base e a mesma; o que muda e so o tipo de chao embaixo dos pes do player.

Uma dica honesta: se o player ainda escorregar um pouco quando a plataforma sobe na vertical, ative Platform On Leave como Add Upward Velocity (ou ajuste conforme o comportamento que voce quer ao sair dela). E um detalhe que so aparece quando voce testa de verdade.

Próximo nível
Quer aprender isso na prática?

No CursoGame.Dev você sai dos tutoriais soltos e constrói jogos publicáveis, com trilha progressiva, quests práticas e feedback real.

Conhecer a plataforma
+500 alunos4.9/5Garantia 7 dias

Movendo com Tween em vez de codigo manual

Mover na unha funciona, mas para um vai e volta suave com pausa nas pontas, um Tween deixa o codigo mais legivel. O ponto de atencao: o Tween por padrao roda no processo de idle (render), e nos queremos fisica. Por isso usamos set_process_mode(Tween.TWEEN_PROCESS_PHYSICS).

extends AnimatableBody2D

@export var deslocamento: Vector2 = Vector2(200, 0)
@export var duracao: float = 2.0
@export var pausa_nas_pontas: float = 0.5

func _ready() -> void:
    var origem := position
    var destino := position + deslocamento

    var tween := create_tween()
    tween.set_loops()
    tween.set_process_mode(Tween.TWEEN_PROCESS_PHYSICS)
    tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)

    tween.tween_property(self, "position", destino, duracao)
    tween.tween_interval(pausa_nas_pontas)
    tween.tween_property(self, "position", origem, duracao)
    tween.tween_interval(pausa_nas_pontas)

O set_loops() sem argumento repete para sempre. O TRANS_SINE com EASE_IN_OUT da aquela desaceleracao nas pontas, que parece bem mais natural do que velocidade constante. As pausas usam tween_interval, que apenas espera sem mexer em nada.

Como o tween esta no modo de fisica e o no e um AnimatableBody2D, o calculo de velocidade continua valendo e o player segue sendo carregado. Se voce ainda nao tinha visto tweens encadeados, vale a leitura sobre animar pelo codigo com Tween, que cobre o encadeamento e os tipos de transicao em mais detalhe.

Seguindo um caminho com Path2D e PathFollow2D

Vai e volta em linha reta resolve muita coisa, mas as vezes voce quer um trajeto curvo, em L, ou um loop. Para isso existe a dupla Path2D + PathFollow2D. O Path2D guarda a curva (que voce desenha no editor), e o PathFollow2D e um no que anda ao longo dela conforme voce muda a propriedade progress ou progress_ratio.

A estrutura fica assim:

# Path2D (com a Curve2D desenhada no editor)
#  └── PathFollow2D
#       └── Plataforma (AnimatableBody2D)
#            ├── CollisionShape2D
#            └── Sprite2D

Um ponto que pega muita gente: o AnimatableBody2D precisa ficar como filho do PathFollow2D para acompanhar o caminho. Mas o PathFollow2D tambem gira a plataforma seguindo a curva. Na maioria das plataformas voce nao quer que a colisao rotacione, entao desligue Rotates no PathFollow2D.

O script abaixo move o PathFollow2D de ida e volta usando progress_ratio (que vai de 0.0 a 1.0 ao longo da curva). Coloque ele no PathFollow2D:

extends PathFollow2D

@export var velocidade: float = 0.3  # fracao da curva por segundo
@export var ida_e_volta: bool = true

var _direcao: float = 1.0

func _physics_process(delta: float) -> void:
    progress_ratio += velocidade * _direcao * delta

    if ida_e_volta:
        if progress_ratio >= 1.0:
            progress_ratio = 1.0
            _direcao = -1.0
        elif progress_ratio <= 0.0:
            progress_ratio = 0.0
            _direcao = 1.0

Se voce quiser um loop continuo num caminho fechado em vez de ida e volta, deixe ida_e_volta como false, ligue Loop no PathFollow2D e deixe o progress_ratio so crescer; ele volta para 0 sozinho ao completar a volta.

A vantagem do Path2D e poder editar o trajeto visualmente no editor sem tocar no codigo. Quer que a plataforma faca uma curva em S? Arraste os pontos da curva e pronto. O script continua o mesmo.

Qual abordagem escolher

Nao existe a melhor opcao para tudo. O que existe e a opcao certa para cada situacao:

  • Movimento reto e simples (elevador, vai e volta no eixo): mover a position no _physics_process resolve com pouco codigo.
  • Movimento suave com pausas e easing: Tween no modo de fisica deixa o codigo claro e facil de ajustar.
  • Trajeto curvo, em L, circular ou que voce quer editar no olho: Path2D + PathFollow2D.

Em todos os tres, a peca que segura tudo e o AnimatableBody2D com sync_to_physics ligado e o movimento acontecendo dentro do passo de fisica. Esse e o ponto que decide se o player vai ser carregado direito ou se vai tremer.

Detalhes que evitam dor de cabeca

Algumas coisas que so aparecem quando voce testa o jogo de verdade:

Plataforma esmagando o player contra uma parede. O move_and_slide() do player tenta deslizar, mas se a plataforma prensa ele contra um colisor estatico, pode haver penetracao. Se isso for um problema no seu jogo, trate a colisao com um sinal body_entered numa Area2D para aplicar dano ou empurrar o player.

Plataforma desaparecendo em cena longa. Se a plataforma faz parte de um cenario com rolagem de fundo, lembre que ela e um objeto de fisica e o fundo nao. Misturar camadas de profundidade com um parallax background ajuda a dar sensacao de movimento sem afetar a colisao, ja que o parallax e puramente visual.

Performance. AnimatableBody2D movido por _physics_process ou por Tween no modo de fisica e barato. Voce pode ter dezenas deles numa fase sem preocupacao. Onde o custo aparece e em colisoes complexas, entao prefira CollisionShape2D com formas simples (retangulos e capsulas) em vez de poligonos detalhados.

Fechando

Uma plataforma movel godot bem feita nao depende de truque, depende de escolher o AnimatableBody2D, manter o sync_to_physics ligado e mover o corpo dentro da fisica, seja por codigo direto, Tween ou Path2D. Com isso o player e carregado de forma natural e voce ganha liberdade para desenhar trajetos do simples ao curvo. Comece pelo vai e volta reto, confirme que o player anda junto sem tremer, e so depois parta para os caminhos mais elaborados. Testar cedo e o que separa uma plataforma que parece certa de uma que so parece certa ate alguem pular em cima dela.