Pipeline de animação de sprites
Importe quadros ordenados ou folhas para Godot 4, Unity 6 ou Phaser 3. Corrija temporização de animação, referências de atlas e pivôs.
Convenções do projeto, versões instaladas, arquitetura, estilo artístico e escolhas explícitas do usuário têm precedência.
Mantenha uma folha e formato funcionais quando a tarefa alterar apenas a temporização; corte e reempacotamento são opcionais.
Este fluxo de trabalho usa arte existente em vez de gerar nova animação; novos quadros vêm de pixo media generate --sheet <C>x<R> --frames (a seção de mídia do prompt), que os escreve já em uma única tela.
Caminho rápido
- Inspecione a folha ou quadros selecionados com
pixo asset info <caminho> --json; leia as definições de clipe atuais. - Confirme tamanho e ordem da célula, intervalos de clipe, linha de base, pivô e temporização para loops ou one-shots.
pixo asset frames check <quadros...> --jsonmede a linha de base e deriva para você. - Escolha o ramo de folha direta ou pacote abaixo; leia os caminhos de saída reais da operação.
- Integre através do proprietário de animação existente do motor sem mover colisão de gameplay.
- Execute
pixo game verify --steps check,build,run --screenshot --json, inspecione logs e quadros, depois assista a um loop completo e one-shot interativamente.
Comandos assumem PIXO_PROJECT_ID; caso contrário, adicione --project <id>.
Caminhos e contagens de quadros abaixo são exemplos; folhas sem metadados não identificam seus próprios clipes.
Unity não tem etapa run nem captura de tela aqui: use --steps check,build e assista aos clipes no Editor.
Escolha a menor alteração de formato
| Entrada ou solicitação | Escolha | Preserve |
|---|---|---|
| Folha regular funcionando, alteração apenas de temporização | SpriteFrames existente, clipe Unity ou folha Phaser | Intervalos de quadros, chave de textura, linha de base compartilhada |
| Grade regular precisa de quadros separados | pixo asset slice --cell LxA ou --grid CxR com um caminho de entrada | Margem, espaçamento e cobertura esperada |
| Quadros oscilam, deslizam ou diferem em tamanho | pixo asset frames check, depois frames align | Ordem de entrada, uma escala para cada quadro |
| PNGs ordenados para Godot | pack --format godot-tres | Ordem de entrada; mantenha PNG e TRES juntos |
| PNGs ordenados para Phaser | pack --format texturepacker-json | Ordem de entrada, chaves reais do descritor |
| Folha ou quadros para Unity | Importe como Sprite e corte no Unity; pack não tem saída Unity | Pivô, Pixels Por Unidade, .meta existente |
| Quadros recortados com pivôs personalizados | Pipeline existente com reconhecimento de metadados | Deslocamentos de recorte e pivôs; empacotamento apenas de imagem não pode recuperá-los |
Registre apenas campos de contrato relevantes: tamanho da tela e célula, ordem linha-por-linha, intervalos de clipe, FPS, retenções de quadro, loop e a linha de base para os pés. Telas de tamanho igual com uma âncora compartilhada evitam oscilação entre quadros; limites opacos não são o pivô.
Corte e âncoras de empacotamento
pixo asset slice public/assets/player.png --cell 32x32 --out derived/player-frames --dry-run --json
pixo asset slice public/assets/player.png --cell 32x32 --out derived/player-frames --json
pixo asset pack sprites/run/frame-0000.png sprites/run/frame-0001.png --format godot-tres --padding 1 --out derived/run-godot --json
pixo asset pack public/sprites/run/frame-0000.png public/sprites/run/frame-0001.png --format texturepacker-json --padding 1 --out public/atlases/run --json
Use os caminhos PNG retornados no relatório de corte; os comandos de pacote de dois quadros apenas ilustram a ordenação.
--grid requer divisão exata após margem e espaçamento; --cell pode deixar células de borda incompletas sem uso.
Verifique a cobertura total e a contagem de quadros. Exclua deliberadamente células vazias e quadros de outros clipes.
Leia results, extraOutputs, reportPath, falhas e originalsPreserved; destinos existentes são ignorados.
Fatos do empacotador:
- O stem deriva da primeira entrada e mantém seus diretórios relativos abaixo de
--out; leia caminhos em vez de adivinhar. - As saídas são
<stem>.atlas.pngmais.atlas.tresou.atlas.json. - O empacotamento pode reorganizar a colocação espacial, mas os descritores preservam a ordem de entrada.
- Sem rotação, recorte, extrusão de borda, nomeação de clipe ou pivôs personalizados são gerados.
- O padding é separação transparente, não pixels de borda duplicados.
Verifique e alinhe quadros
pixo asset frames check public/assets/hero/hero-run-1.png public/assets/hero/hero-run-2.png public/assets/hero/hero-run-3.png --json
pixo asset frames align public/assets/hero/hero-run-*.png --canvas 64x64 --padding 1 --out derived/hero-run --json
Passe os quadros na ordem de reprodução (um glob de shell ordena -10 antes de -2; liste-os quando houver dez ou mais).
frames check não escreve imagens. Por quadro, results[].detail tem os bounds desenhados, bottomGap (linhas abaixo dos pés), feetX (centro das linhas mais baixas, que uma arma balançada não move), empty e touchesEdge.
summary julga o conjunto: baselineSpreadPx (balanço dos pés), feetXSpreadPx (deslizamento), heightDriftPercent, emptyFrames, edgeFrames e uma frase simples por problema em issues; ok é verdadeiro quando não há nenhum.
Uma agachada, compressão ou salto altera a altura propositalmente; a mesma pose em alturas diferentes é deriva de modelo.
frames align escreve cada quadro em <out>/<caminho de entrada>.png em uma tela: pés em uma linha padding acima da parte inferior, feetX na linha central, uma escala para todos para que uma agachada permaneça mais curta que uma posição em pé.
--canvas LxA escala cada quadro pelo mesmo fator para caber; sem ele, a tela é a menor que os comporta a todos.
--match-height primeiro escala cada desenho para a altura mediana, apenas para deriva. --filter nearest mantém pixel art nítido.
Seu summary verifica novamente os quadros alinhados. Saídas existentes são ignoradas, como em toda operação de ativo.
Godot 4: Temporização SpriteFrames
godot-tres emite SpriteFrames formato=3 com um clipe default em loop a 5 FPS.
Mantenha PNG e TRES juntos; a referência de textura é relativa. Importe novas imagens via pixo game verify --steps check --json.
Após substituir o caminho relatado, isto adapta um clipe real de quatro quadros:
func configure_run(sprite: AnimatedSprite2D) -> void:
var packed := load("res://sprites/run/run.atlas.tres") as SpriteFrames
if packed == null or packed.get_frame_count(&"default") != 4:
push_error("Esperados quatro quadros de corrida")
return
var frames := packed.duplicate() as SpriteFrames
frames.rename_animation(&"default", &"run")
frames.set_animation_speed(&"run", 10.0)
frames.set_animation_loop(&"run", true)
frames.set_frame(&"run", 0, frames.get_frame_texture(&"run", 0), 2.0)
sprite.sprite_frames = frames
sprite.centered = true
sprite.offset = Vector2(0, -16) # Exemplo: âncora centro-inferior em uma tela de 32px.
sprite.play(&"run")
Duração de quadro 2.0 significa o dobro da duração normal do quadro, não dois segundos.
Use a linha de base acordada para o offset; mantenha CharacterBody2D e CollisionShape2D estáveis.
Clipes one-shot precisam de loop=false; conecte animation_finished uma vez e controle a transição pela animação ativa.
Referência: Godot 4.3 SpriteFrames.
Phaser 3: Temporização de folha ou atlas
// preload(), para uma folha real de 32px:
this.load.spritesheet('player', 'assets/player.png', { frameWidth: 32, frameHeight: 32 });
// create(), com o intervalo real de corrida do projeto:
if (!this.anims.exists('player-run')) {
this.anims.create({ key: 'player-run',
frames: this.anims.generateFrameNumbers('player', { start: 2, end: 5 }),
frameRate: 10, repeat: -1 });
}
player.setOrigin(0.5, 1).play('player-run', true);
Ativos públicos Vite carregam sem public/ na URL.
Para atlas, this.load.atlas(key, pngUrl, jsonUrl) carrega o par retornado.
As chaves hash do TexturePacker são os caminhos relativos ao projeto de entrada; leia-os ou getFrameNames().
Use uma lista ordenada explícita quando os nomes não codificarem a ordem.
// orderedNames vem da lista de descritor/clipe revisada.
this.anims.create({ key: 'hero-run', frameRate: 10, repeat: -1,
frames: orderedNames.map((frame, index) => ({
key: 'hero-atlas', frame, duration: index === 0 ? 100 : 0,
})),
}); // A 10 FPS, 100 ms extras seguram o primeiro quadro por 200 ms no total.
Proteja a criação global de animação com this.anims.exists como acima; chaves sobrevivem a reinicializações de Scene.
repeat: 0 reproduz uma vez; use um ouvinte de conclusão one-shot próprio.
Alterar a origem afeta a colocação do corpo; inspecione tamanho e offset em vez de mover colisão para esconder um pivô ruim.
Referência: Tipos de animação Phaser 3.90.
Unity 6: Importador, clipe e Animator
Unity não lê godot-tres nem JSON do TexturePacker sem um pacote extra. Coloque a folha em Assets/, defina Texture Type Sprite, Sprite Mode Multiple e os Pixels Per Unit reais. Para pixel art, adicione filtro Point e sem compressão. Corte por tamanho de célula no Sprite Editor, com um pivô compartilhado como Bottom. O corte por script passa por ISpriteEditorDataProvider de SpriteDataProviderFactories; TextureImporter.spritesheet é o caminho antigo. com.unity.2d.aseprite importa arquivos .aseprite diretamente, com clipes, quando a arte começa lá.
Clipes podem ser feitos selecionando sprites e soltando-os na janela Animation, ou a partir de um script quando há muitos. Este exemplo apenas no Editor constrói um clipe de loop de quatro quadros e segura o primeiro quadro:
using System;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
public static class HeroClips
{
[MenuItem("Tools/Create Hero Run Clip")]
public static void CreateRun()
{
const float frame = 0.1f; // 10 FPS.
// LoadAllAssetsAtPath não tem ordem prometida, e hero_10 ordena antes de hero_2 como texto.
var sprites = AssetDatabase.LoadAllAssetsAtPath("Assets/Art/hero.png").OfType<Sprite>()
.OrderBy(sprite => int.Parse(Regex.Match(sprite.name, @"\d+$").Value))
.Skip(2).Take(4).ToArray();
if (sprites.Length != 4) throw new InvalidOperationException("Esperados quatro quadros de corrida");
var keys = sprites.Select((sprite, index) => new ObjectReferenceKeyframe {
time = index == 0 ? 0f : (index + 1) * frame, value = sprite,
}).ToArray();
var clip = new AnimationClip { frameRate = 1f / frame };
AnimationUtility.SetObjectReferenceCurve(clip,
EditorCurveBinding.PPtrCurve("", typeof(SpriteRenderer), "m_Sprite"), keys);
var settings = AnimationUtility.GetAnimationClipSettings(clip);
settings.loopTime = true;
settings.stopTime = (sprites.Length + 1) * frame;
AnimationUtility.SetAnimationClipSettings(clip, settings);
AssetDatabase.CreateAsset(clip, "Assets/Animations/hero_run.anim");
}
}
Tempos de chave são segundos, então uma retenção é um intervalo maior entre chaves. Defina stopTime para que o último quadro tenha sua duração completa.
- No Animator, transições de sprite geralmente querem Has Exit Time desligado e Transition Duration 0, ou a próxima pose chega atrasada.
animator.Play(hash)deixa um estado que já está tocando sozinho, então chamá-lo a cada update é seguro. Reproduzir um one-shot precisa dePlay(hash, 0, 0f). Nomeie hashes uma vez comAnimator.StringToHash.- Detecte o fim de um one-shot com um Animation Event, ou verifique
normalizedTime >= 1enquantoIsInTransition(0)for falso e o hash do estado corresponder. Uma transição pode, de outra forma, relatar o estado antigo. - Coloque o Animator e SpriteRenderer em um filho, com o Rigidbody2D e collider na raiz, e desligue Apply Root Motion.
flipXnão inverte colliders ou objetos filhos, e espelha sobre o pivô, então um pivô descentralizado salta. - Malhas de sprite apertadas podem recortar efeitos desenhados sobre o quadro; use Full Rect quando um shader amostrar além do contorno.
- Um Sprite Atlas agrupa quadros importados separadamente. Dê a ele padding, e desligue Tight Packing e Allow Rotation para pixel art.
Armadilhas: errado → certo
| Errado | Certo, e por quê |
|---|---|
| Ordenar nomes de arquivo não preenchidos lexicograficamente | Ordem explícita; frame-10 caso contrário precede frame-2 |
| Recortar cada quadro independentemente | Mantenha tela ou deslocamentos válidos para que os pés fiquem plantados |
| Adivinhar basenames empacotados | Leia chaves de descritor e caminhos de saída retornados |
| Usar a mesma unidade de duração em todo motor | Godot usa multiplicadores relativos, Phaser adiciona milissegundos, Unity chaves são segundos |
Chamar play(key) a cada update | play(key, true) evita reiniciar um clipe já ativo |
| Deixar a velocidade visual do clipe alterar dano ou física implicitamente | Mantenha a temporização do jogo autoritativa a menos que acoplada explicitamente |
Concluído quando
- Contagem real de quadros, ordem de quadros, temporização de clipe, loop e comportamento one-shot correspondem à solicitação.
- Pés e pivôs permanecem estáveis durante transições entre parado e corrida, espelhamento e reinício;
pixo asset frames checkrelataokpara cada estado, ou seus problemas restantes são deliberados. - Referências de atlas e caminhos de carga são reais; as alterações visuais preservam o comportamento de colisão.
- Use
pixo game run <projectId> --json, ou o Editor no Unity, para assistir a loops completos e conclusão one-shot; uma imagem estática não pode provar temporização. Relate temporizações testadas e problemas não resolvidos. - Inspecione
pixo game verify --steps check,build,run --screenshot --json, incluindo erros de recurso e etapas ignoradas.