本文へスキップ

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で確認しています。

スプライトシート、連番フレーム、GIF・APNG、.asepriteファイルをドロップ
空のStudioを開く
ブラウザ内で処理し、ファイルはアップロードされません。
Studio のスプライト作業画面:48pxのサムライのシートで検出したグリッド(10アニメーション・60フレーム)を適用前にプレビュー
CC0アセット(OpenGameArt)を開いた実際のStudio画面です。
書き出し先
  • 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フィルター、バンドルには可逆・ミップマップなしのインポート設定入り。

使い方

  1. シートを入れて「適用」を押す。
  2. アニメーション名と時間を調整。
  3. パック&書き出しでGodot 4を選ぶ。
  4. フォルダーをプロジェクトにコピーし、.tscnを開く。

出力されるファイル

パック&書き出し › Godot 4は1つのフォルダーを書き出します(ファイル名に由来し、ここではhero)。

ファイル用途
hero.tresSpriteFramesリソース:行またはタグごとにアニメーション1つ(速度・ループ・相対の長さ)、フレームごとにfilter_clipオンのAtlasTextureと、トリムしたフレームを元のセルの大きさに戻すmargin。
hero.pngフレームを新しいPNGにパックし直したもの(トリム、2px間隔、回転なし)。元のシートは参照しません。
hero.tscnこのリソースを使うAnimatedSprite2D:Nearestフィルター、最初のアニメーションを自動再生、centeredオフ、ピボット(指定しなければ下中央)をoffsetに。
hero.png.importGodotのインポート設定:可逆、ミップマップなし、Fix Alpha Borderオフ。
README-GODOT.mdこのバンドルの取り込み手順。

Godot 4に取り込む

  1. バンドルを展開し、フォルダーごとres://以下(例:res://characters/hero/)にコピーします。.tres・PNG・.png.importは一緒に置いてください。リソースは相対パスでPNGを探します。
  2. ファイルシステムドックがPNGを取り込み終えるまで待ちます。同梱の.png.importにより、可逆・ミップマップなしで取り込まれます。
  3. hero.tscnをシーンにドラッグするか、自分のAnimatedSprite2Dを選んでSprite Framesプロパティにhero.tresを読み込みます。
  4. SpriteFramesパネルでアニメーションごとに名前、Speed(変えていなければ10 FPS)、ループの切り替えを確認します。Nerulioで名前を付けていなければrow_Nをここで変えます。
  5. スクリプトでは$Hero.play("run")で切り替えます。ループがオフのアニメーションは最後のフレームで止まってanimation_finishedを出すので、そのシグナルで次のアニメーションを再生します。
  6. ドット絵ならプロジェクト設定 › Rendering › Textures › Canvas Textures › Default Texture FilterをNearestにして、ほかのノードもくっきりさせます。低解像度のゲームには、Godotのドキュメントが Display › Window › Stretch › Mode viewport と Scale Mode integer を勧めています。

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 ScaleSpeedを「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 / 4atlas JSON (multiatlas) · .anims.json検証済み Phaser 3.90 + 4.2両バージョンでフレームとアニメーションを描画。
PixiJS 8spritesheet JSON · animations · anchor · meta.scale検証済み PixiJS 8.21回転・複数ページのアトラスも確認。
Aseprite JSONhash / array · frameTags · slices検証済み Phaser load.aseprite · PixiJS 8.21タグの方向と繰り返し回数を保持。
.asepritelayers · tags · durations · slices検証済み Aseprite 1.3.18Asepriteのコマンドラインで開いて描画。
Spine / libGDX.atlas検証済み spine-canvas 4.2Spineランタイムで回転・トリム領域をすべて描画。libGDX本体は未実行。
Starling / Sparrow XMLXML per page検証済み Phaser 4.2Phaser 3.90はトリムされたXMLフレームを誤って描画します(Phaser側の不具合)。「Sparrow XML (Phaser 3)」プリセットはトリムを切り、3.90・4.2とも合格。
LÖVELua quads · nerulio_atlas.lua · main.lua検証済み LÖVE 11.5同梱ヘルパーで全フレームを描画し、全アニメーションを再生。
Defold.atlas · .tilesourceビルド確認 Defold bob.jar 1.13.1Defoldのコマンドラインビルダーでビルドし、生成テクスチャのUVを読み戻して確認。
GameMakerspr_<name>_stripN.png · gamemaker.json未検証GameMakerでは読み込んでいません(ヘッドレス実行不可)。ストリップはGameMakerの取り込み方式どおりに切ります。
CSS sprites.css · preview .html検証済み Chromium同梱スタイルシートで全クラスを描画。
GIF / APNGone 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 3でも使えますか?

書き出しはGodot 4向けです(4.7.2で検証)。Godot 3は試していません。

元のPNGはそのままで範囲だけ欲しい

できません。書き出しは常にフレームを2px間隔で独自のPNGにパックし直します。トリムを切れば、各範囲がグリッドの1セル全体になります。

無料ですか?アカウントは必要ですか?

このページの機能はすべて無料で、アカウントなしで使えます。透かしや制限された書き出しはありません。

スプライトはアップロードされますか?

いいえ。Studioはこのブラウザのタブ内でデコード・パック・書き出しを行います。プロジェクトはブラウザ(IndexedDB)に自動保存され、.nerulioファイルとして保存できます。

Asepriteやエンジンのプラグインは必要ですか?

いいえ。.asepriteファイルはブラウザで読み書きします。エンジン別のバンドルには必要なものが入っています(Godotはインポート設定とシーン、UnityとGodotのタイルセットは小さなエディタースクリプト)。