Pixel Art Jump Animation: Subida, Ápice e Queda
Pixel art jump animation: antecipação, subida, ápice, queda e aterrissagem com squash and stretch, e a engine trocando frames pela velocidade vertical.
Pixel Art Jump Animation: Subida, Ápice e Queda
Uma pixel art jump animation não é uma animação só: é um conjunto de poses curtas (antecipação, subida, ápice, queda e aterrissagem) que a engine troca de acordo com a velocidade vertical do personagem. Desenhar o pulo como uma sequência fixa de 8 frames funciona no editor e quebra no jogo, porque o tempo no ar muda a cada pulo.
Aqui você vai desenhar cada parte do pulo em 32x32 no Aseprite, aplicar squash and stretch em pixel e ligar tudo à física: com código C# para Unity 6.3 e GDScript para Godot 4 escolhendo o frame pela velocidade vertical.
Por que o pulo não é uma animação só
Num jogo de plataforma bom, o pulo tem altura variável: segurar o botão vai mais alto, soltar cedo corta a subida. Cair de uma plataforma alta dura o dobro de cair de um degrau. Bater a cabeça no teto interrompe a subida no meio. O post de pulo com coyote time e jump buffer mostra como o código faz isso.
Se a animação de pulo tem 8 frames a 80 ms, ela dura 640 ms. Num pulo curto de 400 ms, o personagem pousa ainda com a pose de subida. Numa queda de 1,2 segundo, ele termina a animação no ar e congela no último frame, ou pior, volta ao primeiro em loop.
A solução é desenhar estados, não uma sequência:
| Parte | Quando toca | Frames | Loop |
|---|---|---|---|
| Antecipação | Botão apertado, ainda no chão | 1 | Não |
| Subida | Velocidade vertical para cima, alta | 1 a 2 | Sim, se 2 |
| Ápice | Velocidade vertical perto de zero | 1 | Não |
| Queda | Velocidade vertical para baixo | 1 a 2 | Sim, se 2 |
| Aterrissagem | Tocou o chão vindo do ar | 1 a 2 | Não |
No Aseprite, cada parte vira uma tag: jump_anticipation, jump_up, jump_apex, fall, land. O post de tags de animação no Aseprite explica como nomear para a exportação.
Pixel art jump animation: antecipação e subida
Antecipação. O personagem agacha antes de sair do chão. Corpo 2 pixels mais baixo que a idle, joelhos dobrados, braços para trás. É o frame de squash: o personagem fica mais largo e mais baixo.
Cuidado com o tempo: em plataforma, o pulo precisa sair no mesmo frame em que o botão é apertado. A antecipação não pode atrasar a física. Duas soluções: tocar a antecipação por 1 frame de jogo (cerca de 16 ms a 60 FPS), só para o olho registrar, enquanto o personagem já sobe; ou desenhar a antecipação e usá-la só quando o personagem pousa e pula de novo em seguida.
Subida. O corpo estica: pernas juntas e esticadas para baixo, braços para cima ou junto ao corpo, cabeça erguida. É o frame de stretch: 1 a 2 pixels mais alto e 1 pixel mais estreito que a idle. Se usar 2 frames, o segundo pode ter uma diferença pequena (cabelo ou capa atrasados para baixo) para dar vida em subidas longas.
Ápice
No ponto mais alto, a velocidade vertical chega a zero. O corpo encolhe: joelhos sobem em direção ao peito, braços abrem para equilibrar. É a pose mais "solta" do pulo, e a que comunica o momento de suspensão.
O ápice não deve durar só o instante exato de velocidade zero, senão ninguém vê. Ele toca enquanto a velocidade vertical está numa faixa perto de zero, por exemplo entre +1,5 e -1,5 unidades por segundo. É essa faixa que o código usa logo abaixo.
Queda e aterrissagem
Queda. As pernas descem e se afastam, prontas para pousar. Braços para cima, como quem se segura no ar. Cabelo e capa vão para cima (o ar empurra). Se usar 2 frames em loop alternando o cabelo ou a capa, a queda longa fica viva.
Aterrissagem. O squash mais forte: corpo 2 a 3 pixels mais baixo, joelhos bem dobrados, pés afastados. Dura pouco (60 a 100 ms) e volta para a idle ou para a corrida. Em queda alta, um segundo frame de recuperação vende o impacto. Em jogos com movimento rápido, deixe a aterrissagem ser interrompida pelo input: se o jogador já está correndo, ele não deve esperar o fim do frame.
Desenhe as cinco poses no mesmo canvas, com a linha do chão numa camada guia, e ligue o onion skin para comparar o volume entre elas.
Squash and stretch em pixel
O princípio vem da animação tradicional: um objeto que comprime fica mais largo, um objeto que estica fica mais fino, e o volume total parece o mesmo. Em pixel art, a regra se traduz em contas pequenas:
- Squash (antecipação, aterrissagem): altura do corpo menos 2 pixels, largura mais 1 ou 2.
- Stretch (subida, queda rápida): altura mais 1 ou 2 pixels, largura menos 1.
- Cabeça intacta. Em 32x32, deformar a cabeça destrói o rosto. Aplique o squash e o stretch no tronco e nas pernas.
Duas formas de fazer: redesenhar a pose (melhor resultado, mais trabalho) ou aplicar na engine, escalando o sprite em Y e X por um instante. A segunda é rápida mas deforma os pixels, criando pixels de tamanhos diferentes; em pixel art, prefira desenhar.
Até aqui o pulo existe como arte. Para ele parecer pulo de verdade, o código precisa escolher a pose certa no momento certo, e isso é a parte que separa um protótipo de um personagem gostoso de controlar.
Desenhar o personagem e programar o movimento dele como coisas separadas é o motivo de tanto pulo "estranho" em jogo independente. Produzir as poses já sabendo como a engine vai escolhê-las encurta o caminho até o personagem que você imaginou.
Trocar frame pela velocidade vertical na engine
Unity 6.3. No Animator, crie os estados com os nomes das tags (idle, jump_up, jump_apex, fall, land), cada um com o clipe correspondente. O script lê a velocidade do Rigidbody2D e toca o estado certo. Repare no linearVelocity: no Unity 6, velocity foi substituído por ele.
Arquivo PlayerJumpAnimation.cs:
using UnityEngine;
public class PlayerJumpAnimation : MonoBehaviour
{
[SerializeField] private Rigidbody2D rb;
[SerializeField] private Animator animator;
[SerializeField] private Transform groundCheck;
[SerializeField] private float groundCheckRadius = 0.1f;
[SerializeField] private LayerMask groundLayer;
[SerializeField] private float apexThreshold = 1.5f;
[SerializeField] private float landDuration = 0.1f;
private static readonly int IdleState = Animator.StringToHash("idle");
private static readonly int JumpUpState = Animator.StringToHash("jump_up");
private static readonly int JumpApexState = Animator.StringToHash("jump_apex");
private static readonly int FallState = Animator.StringToHash("fall");
private static readonly int LandState = Animator.StringToHash("land");
private int currentState;
private bool wasGrounded = true;
private float landTimer;
private void Update()
{
bool grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer) != null;
float verticalSpeed = rb.linearVelocity.y;
if (grounded && !wasGrounded)
{
landTimer = landDuration;
}
wasGrounded = grounded;
int nextState;
if (!grounded)
{
if (verticalSpeed > apexThreshold)
{
nextState = JumpUpState;
}
else if (verticalSpeed < -apexThreshold)
{
nextState = FallState;
}
else
{
nextState = JumpApexState;
}
}
else if (landTimer > 0f)
{
landTimer -= Time.deltaTime;
nextState = LandState;
}
else
{
nextState = IdleState;
}
if (nextState != currentState)
{
animator.Play(nextState);
currentState = nextState;
}
}
}
O script só chama Play quando o estado muda, para não reiniciar o clipe a cada frame. No seu jogo, o IdleState do chão é substituído pela sua lógica de locomoção (idle, walk, run). O apexThreshold em 1,5 unidade por segundo é um ponto de partida; aumente se o ápice passar rápido demais para ser visto.
Godot 4. Com AnimatedSprite2D, a lógica é a mesma, lembrando que na Godot o eixo Y aponta para baixo: velocidade negativa é subida.
extends CharacterBody2D
const APEX_THRESHOLD: float = 60.0
@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D
func _update_air_animation() -> void:
if is_on_floor():
return
if velocity.y < -APEX_THRESHOLD:
sprite.play("jump_up")
elif velocity.y > APEX_THRESHOLD:
sprite.play("fall")
else:
sprite.play("jump_apex")
Chame _update_air_animation() no fim do _physics_process, depois do move_and_slide(). Chamar play com a animação que já está tocando não a reinicia, então não precisa guardar estado. O limite está em pixels por segundo; 60 é um bom começo para personagens de 32 pixels.
Testar o pulo antes de desenhar tudo
Antes de caprichar nos detalhes, faça uma versão rascunho das cinco poses só com a silhueta, numa cor chapada, e leve para a engine. Pule de lugares diferentes: do chão para uma plataforma baixa, de uma plataforma alta para o chão, um toque rápido no botão e um pulo segurado até o fim. Observe três coisas:
- O ápice aparece em todos os pulos? Se num pulo curto ele some, aumente a faixa do limite.
- A queda longa fica viva? Se o personagem parece congelado caindo, a queda precisa de um segundo frame em loop ou de um detalhe secundário (cabelo, capa) se mexendo.
- A aterrissagem lê sem atrasar? Se você sente o personagem "grudar" no chão, encurte o frame ou deixe a corrida interromper.
Só depois desse teste vale desenhar o acabamento, com cor, sombra e luz. Ajustar uma silhueta leva um minuto; refazer uma pose finalizada porque o código pede outra leitura leva uma tarde. Esse rascunho também mostra se você precisa de poses extras, como a de pulo duplo (uma cambalhota de 3 ou 4 frames) ou a de deslizar na parede.
Erros comuns
Pulo como animação única. Pose errada em pulo curto ou longo. Estados separados pela velocidade.
Antecipação atrasando o pulo. O jogador sente atraso no controle. A física sai no frame do botão; a antecipação é só visual.
Ápice invisível. O estado só toca com velocidade exatamente zero. Use uma faixa.
Aterrissagem que trava o personagem. Esperar o frame de pouso terminar para andar irrita. Deixe o input interromper.
Squash na cabeça. O rosto deforma. Comprima tronco e pernas.
Escala do sprite na engine em pixel art. Pixels de tamanhos diferentes. Desenhe as poses.
Queda sem loop. Em queda longa, o último frame congela. Loop de 2 frames ou frame único estável.
Próximo passo
Desenhe as cinco poses, teste com pulos de alturas diferentes e ajuste a faixa do ápice até ele aparecer em todo pulo. Depois, una com a parte de controle: aceleração no ar e altura variável estão no post de movimento de personagem 2D de plataforma.
Perguntas frequentes
Quantos frames tem uma animação de pulo em pixel art?
Um pulo completo costuma ter de 4 a 8 frames divididos em partes: 1 de antecipação, 1 ou 2 de subida, 1 de ápice, 1 ou 2 de queda e 1 ou 2 de aterrissagem. Cada parte é uma animação curta separada que a engine escolhe pela situação.
Por que não fazer o pulo como uma animação só?
Porque a duração do pulo muda: pulo curto quando o jogador solta o botão cedo, queda longa de uma plataforma alta, cabeçada no teto. Uma animação de duração fixa nunca bate com a física. Separando em partes, a engine mostra a pose certa para a velocidade vertical do momento.
O que é squash and stretch em pixel art?
É achatar o personagem quando ele comprime (antecipação e aterrissagem) e alongar quando ele se move rápido (subida e queda), mantendo o volume. Em 32x32, isso é 1 ou 2 pixels a menos na altura e a mais na largura, ou o contrário.
Como trocar a animação de pulo pela velocidade na Unity?
Leia a velocidade vertical do Rigidbody2D, que no Unity 6 é rb.linearVelocity.y, e escolha o estado: acima de um limite positivo, subida; abaixo do negativo, queda; entre os dois, ápice. Toque o estado com Animator.Play só quando ele mudar, ou use parâmetros e transições no Animator.


