Godot 4 スプライトシート読み込み · 手作業なしでSpriteFrames
GodotのSpriteFramesのシート用ダイアログは、大きさの違うシートのたびに4×4から始まり、余白や間隔は測れません。ここではピクセルからグリッドを測り、行ごとに名前付きアニメーションを作り、SpriteFramesリソースとすぐ使えるAnimatedSprite2Dシーンで書き出します。
スプライトシートは、たくさんのフレームを行と列に並べた1枚のPNGです。Godot 4ではAnimatedSprite2DがSpriteFramesリソースで再生し、そのリソースにはフレームごとにシートの1領域が入ります。GodotのAdd Frames from Sprite Sheetで自分で作る(列数・行数、またはフレームサイズ・Separation・Offsetを入力)こともできますし、Nerulioにグリッドを測らせ、行ごとに名前付きアニメーションを作って.tres・PNG・シーンで書き出すこともできます。フレームサイズはシートの大きさ ÷ 列数・行数で、384 × 64を6列なら64 × 64です。Godot 4専用で、バンドルはGodot 4.7.2で確認しています。

- Godot 4検証済み· Godot 4.7.2
- Unity 6検証済み· Unity 6000.5.3f1
- Phaser 3 / 4検証済み· Phaser 3.90 + 4.2
- PixiJS 8検証済み· PixiJS 8.21
- Aseprite JSON検証済み· Phaser load.aseprite · PixiJS 8.21
- .aseprite検証済み· Aseprite 1.3.18
- Spine / libGDX検証済み· spine-canvas 4.2
- Starling / Sparrow XML検証済み· Phaser 4.2
- LÖVE検証済み· LÖVE 11.5
- Defoldビルド確認· Defold bob.jar 1.13.1
- GameMaker未検証
- CSS sprites検証済み· Chromium
- GIF / APNGデコード確認· Pillow
スプライトシートとグリッド、Godotに必要なもの
スプライトシートは1キャラクターのフレームを1枚の画像にまとめたもので、左から右、上から下へ読みます。キャラクターのシートは多くの場合1行が1アニメーション(待機・走り・攻撃)で、列はその中の一瞬です。縁も隙間もなければ、フレームの幅はシートの幅 ÷ 列数、高さはシートの高さ ÷ 行数です。
外周の余白やフレーム間の間隔があるシートも少なくありません。その場合シートの幅は「余白 + 列数 × フレーム幅 +(列数 − 1)× 間隔」(右の余白があれば加算)になり、全体の幅を列数で割るとフレームが広すぎます。Godotのシート用ダイアログでは余白をOffset、間隔をSeparationと呼びます。均一なシートはどこでもフレームサイズが同じで、不規則なシート(大きさがばらばらのスプライトやパック済みアトラス)にはグリッドがないため、アトラスのデータかスプライトの輪郭での切り出しが必要です。
Godot 4ではAnimatedSprite2DがSpriteFramesリソースを再生します。名前付きアニメーションごとに毎秒フレーム数(Speed)・ループ・フレーム一覧があり、シートから取ったフレームはシートの矩形領域であるAtlasTextureです。hframes・vframesを使う普通のSprite2Dでも1コマずつ表示できますが、テクスチャ全体を均等に割るだけなので、余白も間隔もないシートにしか合いません。キャンバスアイテムの既定のフィルターはLinearなので、Nearestに変えるまでドット絵はぼやけます。
Nerulioはピクセルから候補のグリッドを測ります。透明な区切り線、絵が繰り返す周期、セル同士の似かた、セルの境界がスプライトを横切る回数を調べ、最有力のグリッドを高・中・低の信頼度と根拠つきでシートに重ねて表示します。「適用」を押すまで何も切りません。別の候補を選ぶ、セルサイズ・オフセット・間隔を手入力する、大きさがばらばらのシートなら輪郭で切る、のいずれもできます。空のセルは飛ばし、行ごとにrow_1、row_2 …のアニメーションができ、名前はタイムラインで変えます。PNGには時間の情報がないため、フレームは100ms(10 FPS)から始まります。
- フレーム(セル)サイズ
- 1フレームの幅 × 高さ(ピクセル)。余白・間隔がなければ、シートの幅 ÷ 列数 × シートの高さ ÷ 行数。
- 余白 / Offset
- シートの端と最初のフレームの間の空きピクセル。GodotのダイアログではOffset。
- 間隔 / Separation
- 隣り合うフレームの間の空きピクセル。GodotのダイアログではSeparation。
- AtlasTexture
- 大きなテクスチャの矩形領域。シートから作ったSpriteFramesのフレームは1つずつこれです。
- Speed(FPS)
- SpriteFramesのアニメーション1つの毎秒フレーム数。各フレームの相対の長さが1ティックに掛かります。
例:フレームサイズ・余白・間隔の計算
同じ6コマの走りを2通りに並べた場合です。
シートA 384 × 64 px、1行 × 6列、余白なし、間隔なし
フレーム幅 = 384 / 6 = 64 フレーム高さ = 64 / 1 = 64 → 64 × 64
Godotのダイアログ:Horizontal 6、Vertical 1 (Sizeが64 × 64になる)
シートB 398 × 68 px、同じフレームに余白2 px・間隔2 px
幅 = 2 + 6 × 64 + 5 × 2 + 2 = 398 高さ = 2 + 64 + 2 = 68
Godotのダイアログ:Size 64 × 64、Separation 2 × 2、Offset 2 × 2
Horizontal 6だけだと398 / 6 = 66 pxのセル:列ごとに2 pxずつずれる
NerulioでシートB:セル64 × 64、余白2、間隔2(信頼度:高)→ row_1、6フレーム
Godotバンドル:speed 10 FPS、durationはすべて1.0(100 ms)、loop on → 1周0.6秒Nerulioのタイムラインでフレームを125msにすると、バンドルは10 FPSのまま全フレームのdurationを1.25にします。1.25 ÷ 10 = 0.125秒です。Godot自体のダイアログは全フレームを1.0で追加するので、そちらではSpeedを変えます(125msなら8 FPS)。
できること
- 絵からグリッド・余白・間隔を測定し、切る前に信頼度つきで表示。
- 行ごと(またはタイムラインで手動)にフレームごとの長さ付きアニメーション。Godotには相対的な長さとループが入ります。
- トリムしてもAtlasTextureの余白で各フレームのオフセットを保つので、フレームが跳ねません。
- シーンはNearestフィルター、バンドルには可逆・ミップマップなしのインポート設定入り。
使い方
- シートを入れて「適用」を押す。
- アニメーション名と時間を調整。
- パック&書き出しでGodot 4を選ぶ。
- フォルダーをプロジェクトにコピーし、.tscnを開く。
出力されるファイル
パック&書き出し › Godot 4は1つのフォルダーを書き出します(ファイル名に由来し、ここではhero)。
| ファイル | 用途 |
|---|---|
hero.tres | SpriteFramesリソース:行またはタグごとにアニメーション1つ(速度・ループ・相対の長さ)、フレームごとにfilter_clipオンのAtlasTextureと、トリムしたフレームを元のセルの大きさに戻すmargin。 |
hero.png | フレームを新しいPNGにパックし直したもの(トリム、2px間隔、回転なし)。元のシートは参照しません。 |
hero.tscn | このリソースを使うAnimatedSprite2D:Nearestフィルター、最初のアニメーションを自動再生、centeredオフ、ピボット(指定しなければ下中央)をoffsetに。 |
hero.png.import | Godotのインポート設定:可逆、ミップマップなし、Fix Alpha Borderオフ。 |
README-GODOT.md | このバンドルの取り込み手順。 |
Godot 4に取り込む
- バンドルを展開し、フォルダーごと
res://以下(例:res://characters/hero/)にコピーします。.tres・PNG・.png.importは一緒に置いてください。リソースは相対パスでPNGを探します。 - ファイルシステムドックがPNGを取り込み終えるまで待ちます。同梱の
.png.importにより、可逆・ミップマップなしで取り込まれます。 hero.tscnをシーンにドラッグするか、自分のAnimatedSprite2Dを選んでSprite Framesプロパティにhero.tresを読み込みます。- SpriteFramesパネルでアニメーションごとに名前、Speed(変えていなければ10 FPS)、ループの切り替えを確認します。Nerulioで名前を付けていなければ
row_Nをここで変えます。 - スクリプトでは
$Hero.play("run")で切り替えます。ループがオフのアニメーションは最後のフレームで止まってanimation_finishedを出すので、そのシグナルで次のアニメーションを再生します。 - ドット絵ならプロジェクト設定 › Rendering › Textures › Canvas Textures › Default Texture FilterをNearestにして、ほかのノードもくっきりさせます。低解像度のゲームには、Godotのドキュメントが Display › Window › Stretch › Mode
viewportと Scale Modeintegerを勧めています。
Nerulioを使わなくても、Godot 4.7は均一なシートを自分で切れます。AnimatedSprite2Dを選んでNew SpriteFramesを作り、SpriteFramesパネルのAdd Frames from Sprite SheetでPNGを開きます。HorizontalとVerticalを入れるか、隙間のあるシートならSize・Separation・Offsetを入れます。Auto Sliceは個数を推測しますが、SeparationとOffsetは0になります。1行分のフレームをクリックし(順序はFrame Order)、Add N Frame(s)を押して、アニメーション名とSpeed(FPS)を決めます。行ごとに繰り返します。全フレームの相対の長さは1.0で、大きさの違うシートを開くとダイアログは4 × 4からやり直しになります。
結果の確認
- SpriteFramesパネルで、各アニメーションのフレーム数がその行の埋まったセルの数と同じはずです。最後に透明なフレームがあれば、空のセルが入っています。
- シーンを実行します。100msのフレーム6枚なら0.6秒ごとに繰り返します。
- 2Dビューポートを400%に拡大します。ピクセルの境界が四角く、フレームの縁に隣のフレームの線が出ていなければ正常です。
- アニメーションを切り替えます。足の位置が動かないはずで、キャラクターが跳ねるならフレームが共通のピボットにそろっていません。
トラブルシューティング
| 症状 | 考えられる原因 | 確認方法 | 対処 |
|---|---|---|---|
| 列が進むほどフレームが少しずつずれる | フレームサイズに間隔が含まれている、または余白と間隔を0のままにした | シートの幅 = オフセット + 列数 × サイズ +(列数 − 1)× 間隔 になるか計算 | Godotに実際のSize・Separation・Offsetを入れるか、Nerulioで測る。フレームサイズの測り方を参照 |
| フレームの縁に隣のフレームが細い線で見える | テクスチャのにじみ:フィルタリングや小数座標でフレームのすぐ外のピクセルを読み、フレーム同士に間隔がない | 動かしながら拡大し、Linearフィルターと小数座標を確認 | Nearestフィルターにし、filter_clipを保つ(バンドルはオン、Sprite2Dの領域ならRegion › Filter Clip)。フレーム間に余白を取る。縁のにじみを参照 |
| スプライトがぼやける | ノードがプロジェクト既定のフィルター(Linear)を継承している | インスペクター › CanvasItem › Texture › Filter | ノードかプロジェクトの既定値をNearestに。Godotのドット絵のぼやけを参照 |
| フレームごとにキャラクターが揺れる | セル内の絵の位置がばらばら、または大きさの違うトリム済みフレームを中央ぞろえしている | Nerulioのタイムラインのオニオンスキンで足の位置を比べる | 書き出す前にフレームをそろえる(バンドルはトリムしたフレームをセルの大きさに戻す)。トリム後の揺れを参照 |
| アニメーションが速すぎる・遅すぎる | Godotのダイアログは全フレームを1.0で追加するので、時間はSpeedだけで決まる。またはSpeed Scaleが1でない | SpriteFramesパネルのSpeed(FPS)、インスペクターのSpeed Scale | Speedを「1000 ÷ フレーム時間(ms)」に(100msなら10 FPS)、またはNerulioでフレームごとの時間を指定。Godotのフレーム時間を参照 |
| Nerulioが間違ったグリッドを提案する(例:48 × 48ではなく48 × 96) | 1フレームの絵が2セルにまたがっている、またはシートに大きさの違うスプライトが混ざっている | 読み込みパネルに候補ごとの信頼度と根拠が出る | 別の候補、カスタムグリッド、輪郭での切り出しから選ぶ。ピクセルが互いに重なったフレームはNerulioでも分けられないので、枠を手で描く |
ほかの方法
| 方法 | こんなときに向いています |
|---|---|
| GodotのAdd Frames from Sprite Sheet(上の手作業の方法) | 均一なシートでアニメーションが1〜2個、フレームレートが一定のとき。ファイルも書き出しの手間も増えません。 |
hframes・vframesを使うSprite2Dと、frameをキーにするAnimationPlayer | すでにAnimationPlayerでほかのプロパティも動かしているとき。余白も間隔もないシートでだけ合います。 |
| PNGではなく元の.asepriteファイル | タグとフレームごとの時間も移せます:AsepriteをGodotへ。 |
| JSON付きのパック済みアトラス | 別のツールでパック済みの、大きさがばらばらのフレーム:TexturePackerをGodotへ。 |
エンジン別の書き出しと検証方法
「検証済み」は、実際のCC0アセットから書き出したファイルを本物のエンジン・ツールで読み込み、元データと比較したという意味です。読み込んでいない形式はそのように表示します。
| 書き出し先 | ファイル | 検証 |
|---|---|---|
| Godot 4 | .tres SpriteFrames · .tscn AnimatedSprite2D · .png.import | 検証済み Godot 4.7.2Godotで読み込み、全アニメーションフレームを描画して元ファイルと比較。シーンはNearestフィルターで、回転は使いません。 |
| Unity 6 | .unity.json · Editor/NerulioSpriteImporter.cs · AnimationClip | 検証済み Unity 6000.5.3f1バッチモードでスプライト範囲・ピボット・ピクセル・クリップのキーと長さを確認。 |
| Phaser 3 / 4 | atlas JSON (multiatlas) · .anims.json | 検証済み Phaser 3.90 + 4.2両バージョンでフレームとアニメーションを描画。 |
| PixiJS 8 | spritesheet JSON · animations · anchor · meta.scale | 検証済み PixiJS 8.21回転・複数ページのアトラスも確認。 |
| Aseprite JSON | hash / array · frameTags · slices | 検証済み Phaser load.aseprite · PixiJS 8.21タグの方向と繰り返し回数を保持。 |
| .aseprite | layers · tags · durations · slices | 検証済み Aseprite 1.3.18Asepriteのコマンドラインで開いて描画。 |
| Spine / libGDX | .atlas | 検証済み spine-canvas 4.2Spineランタイムで回転・トリム領域をすべて描画。libGDX本体は未実行。 |
| Starling / Sparrow XML | XML per page | 検証済み Phaser 4.2Phaser 3.90はトリムされたXMLフレームを誤って描画します(Phaser側の不具合)。「Sparrow XML (Phaser 3)」プリセットはトリムを切り、3.90・4.2とも合格。 |
| LÖVE | Lua quads · nerulio_atlas.lua · main.lua | 検証済み LÖVE 11.5同梱ヘルパーで全フレームを描画し、全アニメーションを再生。 |
| Defold | .atlas · .tilesource | ビルド確認 Defold bob.jar 1.13.1Defoldのコマンドラインビルダーでビルドし、生成テクスチャのUVを読み戻して確認。 |
| GameMaker | spr_<name>_stripN.png · gamemaker.json | 未検証GameMakerでは読み込んでいません(ヘッドレス実行不可)。ストリップはGameMakerの取り込み方式どおりに切ります。 |
| CSS sprites | .css · preview .html | 検証済み Chromium同梱スタイルシートで全クラスを描画。 |
| GIF / APNG | one file per animation | デコード確認 Pillow書き出し後に全フレームと遅延を再デコード。APNGは完全一致。 |
検証の根拠
GIFデコーダー:実在のGIF 29本で408/408フレームがPillowと一致、APNG 16本で132/132。.aseprite:コーパス231ファイルを読み込み・書き直し、Aseprite 1.3.18で開いてタグ・長さ・ピクセルが231/231一致。書き出し:実在のCC0アセットで実際のエンジンを49回実行し47回合格。失敗2回はPhaser 3.90のトリムXMLの不具合で、Phaser 3プリセットで回避できます。
制限
- バンドルはGodot 4専用で、Godot 3はこのリソースを読めません。
- Nerulioはフレームを独自のPNGにパックし直すので、元のシートを直したら書き出し直しが必要です。
- ヒットボックスはリソースのメタデータにだけ入り、当たり判定のノードは作りません。
- グリッド・島の推定は信頼度つきのプレビューで、「適用」を押すまで何も切りません。すべての選択に代替案があり、ワンクリックで切り替えられます。
- レイヤーが正確に合成できない.asepriteファイル(グループの不透明度など)は統合して読み込み、理由を読み込みパネルに表示します。
- 読み込んだアトラス内の回転フレームは回転したままで、その書き出しは未検証です。
- 画像は一辺32,768px(2億6,800万ピクセル)まで。ブラウザのメモリにも依存します。
バージョンと出典
検証の実行では、Godot 4.7.2がNerulioのGodotバンドルを読み込みました。48 × 48のセルに切った288 × 480のサムライのシート(行アニメーション10個・60フレーム)とKenneyのキャラクターシートを含め、全フレームを1倍で描いて元画像と比べ、同梱のシーンを4倍で描いてくっきり表示されることを確かめています。既定の選択だけで、実在のテスト素材16件中16件を正しく切り出しました。Godotのシート用ダイアログの項目名はGodot 4.7のエディターのソースで、ほかのGodotの動作はGodot 4.7の公式ドキュメントで確認しました。
参照した公式ドキュメント
- Godot 4.7 docs: AnimatedSprite2D
- Godot 4.7 docs: SpriteFrames
- Godot 4.7 docs: 2D sprite animation
- Godot 4.7 source: the SpriteFrames editor and its sprite-sheet dialog
- Godot 4.7 docs: Sprite2D (hframes, vframes, region filter clip)
- Godot 4.7 docs: AtlasTexture (filter_clip)
- Godot 4.7 docs: Multiple resolutions (pixel art stretch settings)
- Godot 4.7 docs: ProjectSettings (default texture filter, 2D snap)
よくある質問
Godot 3でも使えますか?
書き出しはGodot 4向けです(4.7.2で検証)。Godot 3は試していません。
元のPNGはそのままで範囲だけ欲しい
できません。書き出しは常にフレームを2px間隔で独自のPNGにパックし直します。トリムを切れば、各範囲がグリッドの1セル全体になります。
無料ですか?アカウントは必要ですか?
このページの機能はすべて無料で、アカウントなしで使えます。透かしや制限された書き出しはありません。
スプライトはアップロードされますか?
いいえ。Studioはこのブラウザのタブ内でデコード・パック・書き出しを行います。プロジェクトはブラウザ(IndexedDB)に自動保存され、.nerulioファイルとして保存できます。
Asepriteやエンジンのプラグインは必要ですか?
いいえ。.asepriteファイルはブラウザで読み書きします。エンジン別のバンドルには必要なものが入っています(Godotはインポート設定とシーン、UnityとGodotのタイルセットは小さなエディタースクリプト)。