この記事について

キャラクターを動かせるようになったら、止まっている間はidle、移動中はrunというように、動作に合わせて絵を切り替えてみましょう。GodotのAnimatedSprite2Dでは、複数の画像をSpriteFramesへ登録してアニメーションを作れます。

この記事では、CharacterBody2Dで上下左右に移動するシーンを土台に、待機と走行の切り替え、左右反転を追加します。Godot 4.6.3のGDScriptを使い、エディターの項目名は英語表記で説明します。壁へ押し付けて実際には動いていないときは、待機アニメーションに戻る仕様です。

この記事でわかること

  • AnimatedSprite2Dへidleとrunのアニメーションを登録する方法
  • 実際の移動速度を使って待機と走行を切り替える方法
  • flip_hで左右を反転し、停止中も最後の向きを保つ方法

基本手順

手順1:AnimatedSprite2Dと6枚の画像を用意する

移動用に作ったプロジェクトを閉じ、フォルダー全体を別名でコピーします。GodotのプロジェクトマネージャーでImportを選び、コピー先のproject.godotを指定して開きます。元のシーンは、Mainの下にGround、Wall、Playerがあり、Playerへ移動用のplayer.gdが付いた構成です。PlayerのPositionは(160, 288)、Motion ModeはFloating、CollisionShape2DのRectangleShape2Dは32×32のまま使います。

Playerの子のSprite2Dを削除し、代わりにAnimatedSprite2Dを追加します。ノード名はAnimatedSprite2Dのままにします。Positionは(0, 0)、Scaleは(1, 1)、Centeredはオンです。CollisionShape2Dは残します。

Main (Node2D)
├ Ground (Polygon2D)
├ Wall (StaticBody2D)
│ ├ Visual (Polygon2D)
│ └ CollisionShape2D
└ Player (CharacterBody2D)
  ├ AnimatedSprite2D
  └ CollisionShape2D

次のリンクからアニメーション用の素材ZIPをダウンロードして展開し、中の6枚のSVG画像をプロジェクトのassetsフォルダーへ入れます。各リンクは同じZIPファイルです。いずれも40×40ピクセルで、右向きのキャラクターです。前の記事のidle_0.svgがすでにある場合は、そのまま使えます。

FileSystemに6枚が表示されたことを確認します。AnimatedSprite2DのInspectorでSprite Framesの空欄からNew SpriteFramesを選び、作成したリソースをクリックして、画面下部のSpriteFramesパネルを開きます。

Playerの子をAnimatedSprite2Dへ変更しSpriteFramesリソースを作った状態
手順1:画像を6枚用意し、AnimatedSprite2Dへ新しいSpriteFramesを設定します。

手順2:待機用のidleを2フレームで作る

SpriteFramesパネルのアニメーション一覧にあるdefaultをダブルクリックし、名前をidleへ変更します。名前は半角小文字です。idleを選択した状態で、FileSystemからidle_0.svg、idle_1.svgの順に、パネルのフレーム欄へドラッグします。

フレーム番号0がidle_0.svg、1がidle_1.svgになっていることを確認します。逆になった場合はフレームをドラッグして並べ直します。Speed(FPS)を2にし、Loopをオンにします。各フレームのDurationは既定の1のままにします。

SpriteFramesパネルの再生ボタンで、2枚が繰り返し切り替わることを確認します。この設定では1枚あたり0.5秒、2枚で1秒の待機アニメーションです。エディター内でのプレビュー再生と、ゲーム実行時の再生開始は別です。実行時の再生は後の手順でスクリプトから指示します。

SpriteFramesのidleに2枚の待機画像を登録し2FPSとLoopを設定した状態
手順2:idleは2枚、2FPS、Loopオンにします。

手順3:走行用のrunを4フレームで作る

SpriteFramesパネルのAdd Animationを押し、新しいアニメーション名をrunにします。runを選び、run_0.svg、run_1.svg、run_2.svg、run_3.svgを番号順にフレーム欄へ追加します。idleを選んだまま画像を追加しないように、左側の選択を確認してください。

runのSpeed(FPS)を8、Loopをオンにします。Durationは4枚とも1です。再生ボタンを押すと、待機より速く足が動きます。この設定では4枚で0.5秒の走行アニメーションになります。

確認が終わったらプレビューを停止します。AnimatedSprite2DのAnimationをidle、Frameを0、Speed Scaleを1にして保存します。Autoplayは設定しなくて構いません。アニメーション名を変える場合は、この後のコードに書く名前もそろえる必要があります。SpriteFramesの作成と画像追加は、公式の2Dスプライトアニメーションの手順でも確認できます。

SpriteFramesのrunに4枚の走行画像を登録し8FPSとLoopを設定した状態
手順3:runは4枚、8FPS、Loopオンにします。

手順4:移動の後にアニメーションを切り替える

Playerに付いているres://player.gdを開き、全体を次の内容に置き換えます。Input Mapは前の記事と同じmove_left、move_right、move_up、move_downを使います。

extends CharacterBody2D

@export var speed: float = 200.0
@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D

func _physics_process(_delta: float) -> void:
	var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
	velocity = direction * speed
	move_and_slide()

	if absf(direction.x) > 0.0:
		sprite.flip_h = direction.x < 0.0
	if get_real_velocity().length() > 1.0:
		sprite.play("run")
	else:
		sprite.play("idle")

@onreadyの行で、Playerの直接の子にあるAnimatedSprite2Dを取得しています。$AnimatedSprite2Dはノード名なので、別の名前を付けている場合はここも変更します。移動部分は、入力からvelocityを設定してmove_and_slide()を呼ぶ、前の記事と同じ処理です。

左右の向きは入力から決めます。direction.xが負なら左向きなのでflip_hをtrueにし、正なら右向きなのでfalseにします。外側のifで横方向の入力があるときだけ更新しているため、上や下だけの移動、キーを離した後は最後の向きを保ちます。画像そのものを反転するので、当たり判定を左右反転する必要はありません。

アニメーションの選択は、move_and_slide()を呼んだ後のget_real_velocity().length()で行います。これは直前の移動処理で実際に動いた速度です。1.0ピクセル毎秒を超えていればrun、それ以下ならidleを再生します。ごく小さい移動まで走行と判定しないよう、0ではなく1.0を境目にしています。

入力があるかだけで判定すると、壁へ向かってキーを押し続けたときも走り続けます。この例は実際の移動を判定するため、壁で止まればidleになります。get_real_velocity()は公式のCharacterBody2Dリファレンスに説明があります。

player.gdでmove_and_slideの後にflip_hとidleまたはrunを更新するコード
手順4:移動処理の後で実際の速度を調べ、idleとrunを切り替えます。

このコードは物理フレームごとにplay()を呼びますが、同じアニメーション名で呼び続けても毎回先頭へ戻るわけではありません。毎フレームstop()やframe = 0を追加すると進行を妨げるため、ここには加えません。再生の詳しい挙動はAnimatedSprite2D.play()の説明を参照してください。

手順5:待機・走行・左右反転を実行して確かめる

シーンとスクリプトを保存して、main.tscnをRun Current Sceneで実行します。Windows・Linuxの標準ショートカットはF6です。まずキーを押さず、待機用の2枚がゆっくり切り替わることを確認します。

次に、次の順で操作します。入力を試す前にゲーム画面をクリックしてください。

  1. 右矢印を押す:右へ動き、runで足が動く
  2. キーを離す:その場で止まり、idleへ戻る
  3. 左矢印を押す:画像が左向きになり、runで左へ動く
  4. 左矢印を離して上矢印だけを押す:左向きを保ったまま上へ動く
  5. 壁の左側から右矢印を押し続ける:壁で止まった後は、右向きのidleになる
  6. 壁に当たった状態で右矢印と上矢印を押す:壁沿いに上へ移動し、runになる
実行中の待機idle、走行run、左向き反転を比較した状態
手順5:動作だけでなく、停止時と上下移動中に最後の向きが残ることも確かめます。
右キーで壁に押し付けた後、実際の速度が0となりidleへ戻った実行画面
手順5:壁で止まるとActual speedは0になり、idleへ戻ります。

完成サンプルのHUDには、位置と実際の速度に加え、idle:0のような「アニメーション名:フレーム番号」とFlipが表示されます。Flipがtrueなら左右反転中です。この表示は観察用で、アニメーションを切り替える処理自体はPlayerのスクリプトだけで行っています。

うまくいかないときの確認箇所

画像が表示されない、アニメーションが見つからない

AnimatedSprite2DのSprite Framesにリソースが設定されているか、idleとrunの両方に画像が入っているかを確認します。コードの文字列とアニメーション名は、大文字・小文字も含めて一致させます。IdleやRunという名前なら、掲載コードのidleやrunとは別の名前です。

Node not foundというエラーになる

Playerの直接の子にAnimatedSprite2Dがあるか確認します。スクリプトをMainに付けたり、AnimatedSprite2Dを別のノードの下へ移したりすると、$AnimatedSprite2Dで取得できません。ノード構成とスクリプトの取付先を手順1にそろえます。

絵が1枚目のまま動かない、一度しか再生されない

Speed(FPS)がidleでは2、runでは8になっているか、AnimatedSprite2DのSpeed Scaleが1になっているかを確認します。一度で止まる場合は、対象アニメーションのLoopをオンにします。毎フレームstop()を呼んだり、frameを0へ戻したりする処理が残っていないかも調べます。

壁で止まっているのにrunになる

切り替え条件が入力の有無になっていないか、get_real_velocity()をmove_and_slide()より前で読んでいないか確認します。ただし、壁沿いに上下へ滑っているときは実際に移動しているのでrunになります。真正面から壁へ押し付けた状態で比較してください。

止まるたびに右向きへ戻る

sprite.flip_h = direction.x < 0.0を無条件に実行すると、停止中のdirection.xは0なのでfalseになります。掲載コードのように、横方向の入力があるときだけflip_hを変更します。素材が左向きで作られている場合は、左右反転の条件を逆にする必要があります。

まとめ

AnimatedSprite2Dでは、SpriteFramesへ名前付きのアニメーションを登録し、play(“idle”)やplay(“run”)で切り替えます。この例では移動後の実速度を使い、壁に止められたときも自然に待機へ戻るようにしました。

アニメーションの選択と左右の向きは別々に考えると整理しやすくなります。実際の移動でidleとrunを選び、横方向の入力があるときだけflip_hを更新すれば、停止中にも最後の向きを保てます。