Que fait Pipeline d'animation de sprites ?
Importez des images ordonnées ou des feuilles de sprites dans Godot 4, Unity 6 ou Phaser 3. Corrigez le timing d'animation, les références d'atlas et les pivots.
Les conventions de projet, les versions installées, l'architecture, le style artistique et les choix explicites de l'utilisateur sont prioritaires.
Conservez une feuille et un format fonctionnels lorsque la tâche ne change que le timing ; le découpage et le réempaquetage sont facultatifs.
Ce workflow utilise des assets existants plutôt que de générer de nouvelles animations ; les nouvelles images proviennent de pixo media generate --sheet <C>x<R> --frames (la section média du prompt), qui les écrit déjà sur une seule toile.
Chemin rapide
- Inspectez la feuille ou les images sélectionnées avec
pixo asset info <chemin> --json; lisez les définitions des clips actuels. - Confirmez la taille et l'ordre des cellules, les plages de clips, la ligne de base, le pivot et le timing pour les boucles ou les plans uniques.
pixo asset frames check <images...> --jsonmesure la ligne de base et la dérive pour vous. - Choisissez la branche directe-feuille ou empaquetage ci-dessous ; lisez les chemins de sortie réels de l'opération.
- Intégrez via le propriétaire d'animation existant du moteur sans déplacer la collision de gameplay.
- Exécutez
pixo game verify --steps check,build,run --screenshot --json, inspectez les journaux et les images, puis regardez une boucle complète et un plan unique de manière interactive.
Les commandes supposent PIXO_PROJECT_ID ; sinon ajoutez --project <id>.
Les chemins et les nombres d'images ci-dessous sont des exemples ; les feuilles sans métadonnées n'identifient pas leurs propres clips.
Unity n'a pas d'étape run ni de capture d'écran ici : utilisez --steps check,build et regardez les clips dans l'Éditeur.
Choisissez le plus petit changement de format
| Entrée ou demande | Choisissez | Préservez |
|---|---|---|
| Feuille régulière fonctionnelle, changement de timing uniquement | SpriteFrames existant, clip Unity ou feuille Phaser | Plages d'images, clé de texture, ligne de base partagée |
| Grille régulière nécessitant des images séparées | pixo asset slice --cell LxH ou --grid CxR avec un chemin d'entrée | Marge, espacement et couverture attendue |
| Les images vacillent, glissent ou diffèrent en taille | pixo asset frames check, puis frames align | Ordre d'entrée, une échelle pour chaque image |
| PNG ordonnés pour Godot | pack --format godot-tres | Ordre d'entrée ; gardez PNG et TRES ensemble |
| PNG ordonnés pour Phaser | pack --format texturepacker-json | Ordre d'entrée, clés de descripteur réelles |
| Feuille ou images pour Unity | Importer en tant que Sprite et découper dans Unity ; pack n'a pas de sortie Unity | Pivot, Pixels Par Unité, .meta existant |
| Images rognées avec pivots personnalisés | Pipeline existant avec métadonnées | Décalages de rognage et pivots ; l'empaquetage d'images seules ne peut pas les récupérer |
Enregistrez uniquement les champs de contrat pertinents : taille de la toile et des cellules, ordre ligne par ligne, plages de clips, FPS, durées d'image, boucle et ligne de base pour les pieds. Des toiles de taille égale avec un ancrage partagé évitent le vacillement d'image à image ; les limites opaques ne sont pas le pivot.
Découpage et empaquetage d'ancrages
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
Utilisez les chemins PNG retournés par le rapport de découpage ; les commandes d'empaquetage à deux images n'illustrent que l'ordre.
--grid nécessite une division exacte après la marge et l'espacement ; --cell peut laisser des cellules de bordure incomplètes inutilisées.
Vérifiez la couverture complète et le nombre d'images. Excluez délibérément les cellules vides et les images d'autres clips.
Lisez results, extraOutputs, reportPath, les échecs et originalsPreserved ; les destinations existantes sont ignorées.
Faits sur l'empaquetage :
- Le nom de base dérive de la première entrée et conserve ses répertoires relatifs sous
--out; lisez les chemins plutôt que de deviner. - Les sorties sont
<stem>.atlas.pngplus.atlas.tresou.atlas.json. - L'empaquetage peut réorganiser le placement spatial mais les descripteurs préservent l'ordre d'entrée.
- Aucune rotation, rognage, extrusion de bord, nommage de clip ou pivot personnalisé n'est généré.
- Le remplissage est une séparation transparente, pas des pixels de bord dupliqués.
Vérifier et aligner les images
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
Passez les images dans l'ordre de jeu (un glob shell trie -10 avant -2 ; listez-les lorsqu'il y en a dix ou plus).
frames check n'écrit aucune image. Par image, results[].detail a les bounds dessinés, bottomGap (rangées sous les pieds), feetX (centre des rangées les plus basses, qu'une arme balancée ne déplace pas), empty et touchesEdge.
summary juge l'ensemble : baselineSpreadPx (balancement des pieds), feetXSpreadPx (glissement), heightDriftPercent, emptyFrames, edgeFrames et une phrase simple par problème dans issues ; ok est vrai quand il n'y en a pas.
Une position accroupie, un écrasement ou un saut change la hauteur intentionnellement ; la même pose à différentes hauteurs est une dérive du modèle.
frames align écrit chaque image dans <out>/<chemin d'entrée>.png sur une seule toile : les pieds sur une ligne padding au-dessus du bas, feetX sur la ligne centrale, une échelle pour toutes afin qu'une position accroupie reste plus courte qu'une position debout.
--canvas LxH met à l'échelle chaque image par le même facteur pour l'adapter ; sans cela, la toile est la plus petite qui les contient tous.
--match-height met d'abord à l'échelle chaque dessin à la hauteur médiane, pour la dérive uniquement. --filter nearest garde le pixel art net.
Son summary revérifie les images alignées. Les sorties existantes sont ignorées, comme pour chaque opération sur les assets.
Godot 4 : timing SpriteFrames
godot-tres émet SpriteFrames format=3 avec un clip default en boucle à 5 FPS.
Gardez PNG et TRES ensemble ; la référence de texture est relative. Importez les nouvelles images via pixo game verify --steps check --json.
Après avoir substitué le chemin rapporté, cela adapte un clip réel de quatre images :
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("Expected four run frames")
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) # Exemple : ancre bas-centre sur une toile de 32px.
sprite.play(&"run")
La durée d'image 2.0 signifie deux fois la durée d'image normale, pas deux secondes.
Utilisez la ligne de base convenue pour le décalage ; gardez CharacterBody2D et CollisionShape2D stables.
Les clips à plan unique nécessitent loop=false ; connectez animation_finished une seule fois et verrouillez la transition par l'animation active.
Référence : Godot 4.3 SpriteFrames.
Phaser 3 : timing de feuille ou d'atlas
// preload(), pour une feuille réelle de 32px :
this.load.spritesheet('player', 'assets/player.png', { frameWidth: 32, frameHeight: 32 });
// create(), avec la plage de course réelle du projet :
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);
Les assets publics Vite se chargent sans public/ dans l'URL.
Pour les atlas, this.load.atlas(key, pngUrl, jsonUrl) charge la paire retournée.
Les clés de hachage TexturePacker sont les chemins relatifs au projet d'entrée ; lisez-les ou getFrameNames().
Utilisez une liste ordonnée explicite lorsque les noms n'encodent pas l'ordre.
// orderedNames provient de la liste de descripteurs/clips examinée.
this.anims.create({ key: 'hero-run', frameRate: 10, repeat: -1,
frames: orderedNames.map((frame, index) => ({
key: 'hero-atlas', frame, duration: index === 0 ? 100 : 0,
})),
}); // À 10 FPS, 100 ms supplémentaires maintiennent la première image pour 200 ms au total.
Protégez la création d'animations globales avec this.anims.exists comme ci-dessus ; les clés survivent aux redémarrages de Scène.
repeat: 0 joue une seule fois ; utilisez un écouteur de fin de plan unique dédié.
Changer l'origine affecte le placement du corps ; inspectez la taille et le décalage plutôt que de déplacer la collision pour masquer un mauvais pivot.
Référence : Phaser 3.90 types d'animation.
Unity 6 : importateur, clip et Animator
Unity ne lit ni godot-tres ni le JSON de TexturePacker sans un package supplémentaire. Placez la feuille sous Assets/, puis définissez Texture Type Sprite, Sprite Mode Multiple et les Pixels Per Unit réels. Pour le pixel art, ajoutez le filtre Point et pas de compression. Découpez par taille de cellule dans l'éditeur de sprite, avec un pivot partagé comme Bottom. Le découpage scripté passe par ISpriteEditorDataProvider depuis SpriteDataProviderFactories ; TextureImporter.spritesheet est l'ancien chemin. com.unity.2d.aseprite importe les fichiers .aseprite directement, avec les clips, lorsque l'art commence là.
Les clips peuvent être créés en sélectionnant des sprites et en les déposant dans la fenêtre d'animation, ou depuis un script lorsqu'il y en a beaucoup. Cet exemple uniquement pour l'Éditeur construit un clip en boucle de quatre images et maintient la première image :
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'a pas d'ordre promis, et hero_10 se trie avant hero_2 en tant que texte.
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("Expected four run frames");
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");
}
}
Les temps des clés sont en secondes, donc un maintien est un écart plus large entre les clés. Définissez stopTime pour que la dernière image ait sa durée complète.
- Dans l'Animator, les transitions de sprite veulent généralement Has Exit Time désactivé et Transition Duration 0, sinon la pose suivante arrive en retard.
animator.Play(hash)laisse un état qui joue déjà seul, donc l'appeler à chaque mise à jour est sûr. Rejouer un plan unique nécessitePlay(hash, 0, 0f). Hachez les noms une fois avecAnimator.StringToHash.- Détectez la fin d'un plan unique avec un Animation Event, ou vérifiez
normalizedTime >= 1tandis queIsInTransition(0)est faux et que le hash d'état correspond. Une transition peut sinon rapporter l'ancien état. - Mettez l'Animator et le SpriteRenderer sur un enfant, avec le Rigidbody2D et le collider sur la racine, et désactivez Apply Root Motion.
flipXne retourne pas les colliders ou les objets enfants, et il reflète autour du pivot, donc un pivot décentré saute. - Les maillages de sprite serrés peuvent couper les effets dessinés sur l'image ; utilisez Full Rect lorsqu'un shader échantillonne au-delà du contour.
- Un Sprite Atlas regroupe les images importées séparément. Donnez-lui du remplissage, et désactivez Tight Packing et Allow Rotation pour le pixel art.
Pièges : mauvais → bon
| Mauvais | Bon, et pourquoi |
|---|---|
| Trier les noms de fichiers sans remplissage lexicographiquement | Ordre explicite ; frame-10 précède sinon frame-2 |
| Rogner chaque image indépendamment | Gardez la toile ou des décalages valides pour que les pieds restent plantés |
| Deviner les noms de base empaquetés | Lisez les clés de descripteur et les chemins de sortie retournés |
| Utiliser la même unité de durée dans chaque moteur | Godot utilise des multiplicateurs relatifs, Phaser ajoute la durée d'image en millisecondes, Unity les clés sont en secondes |
Appeler play(clé) à chaque mise à jour | play(clé, true) évite de redémarrer un clip déjà actif |
| Laisser la vitesse visuelle du clip changer les dégâts ou la physique implicitement | Gardez le timing du gameplay comme autorité sauf couplage explicite |
Terminé quand
- Le nombre réel d'images, l'ordre des images, le timing du clip, la boucle et le comportement d'un plan unique correspondent à la demande.
- Les pieds et les pivots restent stables lors des transitions entre repos et course, du miroir et du redémarrage ;
pixo asset frames checkrapporteokpour chaque état, ou ses problèmes restants sont délibérés. - Les références d'atlas et les chemins de chargement sont réels ; les changements visuels préservent le comportement de collision.
- Utilisez
pixo game run <projectId> --json, ou l'Éditeur sur Unity, pour regarder les boucles complètes et l'achèvement des plans uniques ; une image fixe ne peut pas prouver le timing. Rapportez les timings testés et les problèmes non résolus. - Inspectez
pixo game verify --steps check,build,run --screenshot --json, y compris les erreurs de ressources et les étapes ignorées.