精靈動畫管道 是做什麼的?
將有序影格或工作表匯入 Godot 4、Unity 6 或 Phaser 3。修正動畫時序、圖集參考和樞軸。
專案慣例、已安裝版本、架構、美術風格和明確的使用者選擇優先。
當任務僅變更時序時,保留現有的工作表和格式;切片和重新打包為可選。
此工作流程使用現有美術,而非生成新動畫;新影格來自 pixo media generate --sheet <C>x<R> --frames(提示的媒體部分),它會將影格寫入同一個畫布。
快速路徑
- 使用
pixo asset info <path> --json檢查所選的工作表或影格;讀取目前的片段定義。 - 確認儲存格大小和順序、片段範圍、基準線、樞軸以及循環或一次性動畫的時序。
pixo asset frames check <frames...> --json為您測量基準線和偏移。 - 選擇下方的直接工作表或打包分支;讀取操作實際的輸出路徑。
- 透過引擎現有的動畫擁有者整合,而不移動遊戲碰撞。
- 執行
pixo game verify --steps check,build,run --screenshot --json,檢查日誌和影格,然後互動式地觀看完整循環和一次性動畫。
指令假設已設定 PIXO_PROJECT_ID;否則需加上 --project <id>。
以下路徑和影格計數為範例;無中繼資料的工作表無法識別自己的片段。
Unity 沒有 run 步驟或截圖:請使用 --steps check,build 並在編輯器中觀看片段。
選擇最小的格式變更
| 輸入或請求 | 選擇 | 保留 |
|---|---|---|
| 工作正常的工作表,僅變更時序 | 現有的 SpriteFrames、Unity 片段或 Phaser 工作表 | 影格範圍、紋理鍵、共享基準線 |
| 常規網格需要分離影格 | pixo asset slice --cell WxH 或 --grid CxR 加上輸入路徑 | 邊距、間距和預期覆蓋範圍 |
| 影格抖動、滑動或尺寸不同 | pixo asset frames check,然後 frames align | 輸入順序、所有影格使用一個縮放比例 |
| 用於 Godot 的有序 PNG | pack --format godot-tres | 輸入順序;保持 PNG 和 TRES 在一起 |
| 用於 Phaser 的有序 PNG | pack --format texturepacker-json | 輸入順序、實際的描述符鍵 |
| 用於 Unity 的工作表或影格 | 匯入為 Sprite 並在 Unity 中切片;pack 沒有 Unity 輸出 | 樞軸、每單位像素、現有的 .meta |
| 帶自訂樞軸的裁切影格 | 現有的中繼資料感知管道 | 裁切偏移和樞軸;僅影像打包無法恢復它們 |
僅記錄相關的合約欄位:畫布和儲存格大小、行優先順序、片段範圍、FPS、影格保持、循環以及腳的基準線。 具有共享錨點的等尺寸畫布可避免影格間抖動;不透明邊界不是樞軸。
切片和打包錨點
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
使用切片報告回傳的 PNG 路徑;兩個影格的打包指令僅用於說明順序。
--grid 要求在邊距和間距後精確分割;--cell 可能留下不完整的邊緣儲存格未被使用。
檢查完整覆蓋範圍和影格計數。刻意排除其他片段的空白儲存格和影格。
讀取 results, extraOutputs, reportPath, failures 和 originalsPreserved;現有目標將被跳過。
打包器事實:
- 主檔名衍生自第一個輸入並保留其在
--out下的相對目錄;讀取路徑而不是猜測。 - 輸出為
<stem>.atlas.png加上.atlas.tres或.atlas.json。 - 打包可能會重新排列空間位置,但描述符保留輸入順序。
- 不會生成旋轉、裁切、邊緣擠出、片段命名或自訂樞軸。
- 內邊距是透明分隔,而不是重複的邊緣像素。
檢查和對齊影格
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
按播放順序傳遞影格(shell glob 會將 -10 排在 -2 之前;當有十個或更多影格時請列出它們)。
frames check 不會寫入影像。每個影格,results[].detail 包含繪製的 bounds, bottomGap(腳下的行數), feetX(最低行的中心,揮動的武器不會移動它), empty 和 touchesEdge。
summary 判斷集合:baselineSpreadPx(腳部跳動), feetXSpreadPx(滑動), heightDriftPercent, emptyFrames, edgeFrames 以及 issues 中每個問題的一條簡潔句子;ok 在沒有問題時為 true。
下蹲、壓縮或跳躍會故意改變高度;不同高度的相同姿勢是模型偏移。
frames align 將每個影格寫入 <out>/<input path>.png 的一個畫布上:腳在離底部 padding 的一條線上,feetX 在中間線上,所有影格使用一個縮放比例,因此下蹲時比站立時更短。
--canvas WxH 將每個影格縮放到相同的比例以適應;沒有它時,畫布是能容納所有影格的最小尺寸。
--match-height 首先將每個繪圖縮放到中位數高度,僅用於偏移。--filter nearest 保持像素藝術清晰。
其 summary 重新檢查對齊後的影格。與所有資產操作一樣,現有輸出將被跳過。
Godot 4:SpriteFrames 時序
godot-tres 發出格式=3 的 SpriteFrames,其中有一個以 5 FPS 循環的 default 片段。
保持 PNG 和 TRES 在一起;紋理引用是相對的。透過 pixo game verify --steps check --json 匯入新影像。
在替換報告的路徑後,以下程式碼調整了一個實際的四影格片段:
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) # 範例:32px 畫布上的底部中心錨點。
sprite.play(&"run")
影格持續時間 2.0 表示正常影格持續時間的兩倍,而不是兩秒。
使用約定的基準線作為偏移;保持 CharacterBody2D 和 CollisionShape2D 穩定。
一次性片段需要 loop=false;連接 animation_finished 一次並根據活動動畫來閘控轉換。
參考:Godot 4.3 SpriteFrames。
Phaser 3:工作表或圖集時序
// preload(),針對實際的 32px 工作表:
this.load.spritesheet('player', 'assets/player.png', { frameWidth: 32, frameHeight: 32 });
// create(),使用專案實際的運行範圍:
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);
Vite 公開資產載入時 URL 中不含 public/。
對於圖集,this.load.atlas(key, pngUrl, jsonUrl) 載入回傳的配對。
TexturePacker 雜湊鍵是輸入的專案相對路徑;讀取它們或使用 getFrameNames()。
當名稱不編碼順序時,使用明確的有序列表。
// orderedNames 來自審閱過的描述符/片段列表。
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 額外毫秒會將第一個影格保持總共 200 毫秒。
如上所述,使用 this.anims.exists 保護全域動畫創建;鍵在場景重啟後仍然存在。
repeat: 0 播放一次;使用擁有的一次性完成監聽器。
變更原點會影響身體放置;檢查大小和偏移,而不是移動碰撞來隱藏糟糕的樞軸。
參考:Phaser 3.90 動畫類型。
Unity 6:匯入器、片段和動畫器
沒有額外套件時,Unity 既無法讀取 godot-tres 也無法讀取 TexturePacker JSON。將工作表放入 Assets/ 下,然後設定紋理類型為 Sprite、Sprite 模式為 Multiple 以及實際的每單位像素。對於像素藝術,新增 Point 濾鏡且不壓縮。在 Sprite 編輯器中按儲存格大小切片,使用共享樞軸(例如 Bottom)。腳本化切片透過 SpriteDataProviderFactories 的 ISpriteEditorDataProvider 進行;TextureImporter.spritesheet 是舊路徑。com.unity.2d.aseprite 直接匯入 .aseprite 檔案,包含片段,當藝術從那裡開始時。
可以透過選擇精靈並將它們拖放到動畫視窗來建立片段,或者當有很多片段時透過腳本建立。這個僅限編輯器的範例建立了一個四影格循環片段並保持第一個影格:
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 沒有保證的順序,且 hero_10 作為文字排在 hero_2 之前。
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");
}
}
關鍵時間是以秒為單位,因此保持是關鍵之間更寬的間隔。設定 stopTime 使最後一個影格獲得其完整長度。
- 在動畫器中,精靈轉換通常希望關閉 Has Exit Time 並將 Transition Duration 設為 0,否則下一個姿勢會遲到。
animator.Play(hash)會留下一個已經在播放的狀態,所以每次更新都呼叫它是安全的。重播一次性動畫需要Play(hash, 0, 0f)。使用Animator.StringToHash一次命名雜湊。- 使用動畫事件檢測一次性動畫的結束,或者在
IsInTransition(0)為 false 且狀態雜湊相符時檢查normalizedTime >= 1。否則,轉換可能會報告舊狀態。 - 將動畫器和 SpriteRenderer 放在子物體上,將 Rigidbody2D 和碰撞器放在根物體上,並關閉 Apply Root Motion。
flipX不會翻轉碰撞器或子物件,並且它會圍繞樞軸鏡像,因此偏離中心的樞軸會跳動。 - 緊密的精靈網格可能會裁剪繪製在影格上的特效;當著色器在輪廓之外取樣時,請使用 Full Rect。
- Sprite Atlas 會批次處理單獨匯入的影格。為其指定內邊距,並關閉 Tight Packing 和 Allow Rotation 以獲得像素藝術。
陷阱:錯誤 → 正確
| 錯誤 | 正確及其原因 |
|---|---|
| 按字典順序排序無填充的檔名 | 明確的順序;否則 frame-10 會排在 frame-2 之前 |
| 獨立裁切每個影格 | 保持畫布或有效偏移,使腳穩定著陸 |
| 猜測打包的基底名稱 | 讀取描述符鍵和回傳的輸出路徑 |
| 在每個引擎中使用相同的持續時間單位 | Godot 使用相對乘數,Phaser 影格持續時間增加毫秒,Unity 鍵是秒 |
每次更新都呼叫 play(key) | play(key, true) 避免重新啟動已經活動的片段 |
| 讓視覺片段速度隱含地改變傷害或物理 | 保持遊戲時序權威,除非明確耦合 |
完成時
- 實際影格計數、影格順序、片段時序、循環和一次性行為與請求相符。
- 腳和樞軸在閒置和跑步之間的轉換、鏡像和重新啟動期間保持穩定;
pixo asset frames check報告每個狀態的ok,或者其剩餘問題是有意為之。 - 圖集參考和載入路徑是真實的;視覺變更保留碰撞行為。
- 使用
pixo game run <projectId> --json,或在 Unity 上使用編輯器,觀看完整的循環和一次性動畫完成;靜止影像無法證明時序。報告測試過的時序和未解決的問題。 - 檢查
pixo game verify --steps check,build,run --screenshot --json,包括資源錯誤和跳過的步驟。