【Godot】GodotのAnimationPlayer入門:キーを打って、踏むと開く扉を作る

作成: 2026-09-22最終更新: 2026-10-10

AnimationPlayerでキーを2つ打ち、スイッチを踏むと開いて離れると閉まる扉を作る方法を解説します。

スイッチを踏むと開き、離れると閉まる扉のように、決まった動きを再生したいときは、AnimationPlayer でキーを打ちます。開始と終わりの2つのキーを打てば、そのあいだの動きは Godot が埋めてくれます。

ただ、キーを打ったつもりでも、再生すると動かないことがよくあります。タイムラインの1行がインスペクタの1項目と対応している、という仕組みが見えていないと、どこを直せばいいのか分かりません。

この記事では、タイムラインとインスペクタの対応をつかみ、スイッチを踏むと開く扉を作る方法を解説します。

インスペクタのPositionとタイムラインの1行がつながり、針を0.25秒に置くとyは268になる

この記事でわかること

  • タイムラインの1行とインスペクタの1項目の対応、鍵アイコンが何を書き込むのか
  • 針・値・鍵を押す順番と、その順番を崩したときに起きること
  • キーを打ったのに再生しても動かないときに、確かめる4つの点
  • 逆再生がどこから始まるか、再生が終わったアニメの名前がどこに残るか

動作確認環境: Godot 4.7

Sponsored

タイムラインとインスペクタの対応

AnimationPlayer を選ぶと、画面下に Animation パネルが開きます。ここで新しいアニメーションを作ると、左半分にトラック(動かす項目ごとの行)の一覧、右半分に時間の目盛りが並んだ画面になります。目盛りの上には、いまの時刻を指す縦の線(再生位置の針)があります。

この状態でノードを選ぶと、インスペクタの各項目の右端に鍵のアイコンが出ます。これを押すと「この時刻の、この項目は、いまこの値」という1点が、その項目の行に記録されます。この1点がキーです。

インスペクタの項目の鍵を押すと、その項目を担当する1行がタイムラインにでき、キーが並ぶ

トラックの一覧に並ぶ1行は、どのノードの、どの項目か を指しています。Door:position という行は、Door というノードの position を担当します。Sprite2D:modulate なら、Sprite2D の色です。

扉を閉じた位置から開いた位置まで動かすには、同じ行に時刻と値の違うキーが2つ要ります。0.00秒に (320, 300)、0.50秒に (320, 236) と入っていれば、再生したときにその間を埋めた値が流れます。この「間を埋める」計算を補間と呼びます。

絵を切り替えるためだけの道具ではなく、鍵が出る項目なら、位置でも色でも角度でも同じやり方で動かせます。絵の切り替わりに判定や音をそろえる話は AnimationPlayerで攻撃を1本にまとめる記事 にあります。

他のエンジンでいうと: Godot は AnimationPlayer でプロパティの変化を再生します。扉のように時間に沿って物を動かす用途は、Unity の Animation ウィンドウで作る Animation Clip や、Unreal Engine の Timeline を使った実装に近いものです。

鍵を押す順番

キーが打てない原因のほとんどは、順番です。

針を動かし、値を確かめ、鍵を押す。値を変えてから針を動かすと、変えた値が戻ってしまう
  1. 針を 0.00 秒へ動かす
  2. 閉じている状態の値をインスペクタで確認する
  3. 鍵を押す
  4. 針を 0.50 秒へ動かす
  5. 開いた状態の値を入れて、もう一度鍵を押す

針を動かすのは、値を変える前だけです。値を変えたあとに針を動かすと、移動先の時刻の値で上書きされます。すでにトラックがあると、針を動かすたびにその時刻の値が流し込まれるためです。

「扉を動かしてから時刻を決めよう」という順番が、いちばんよくある詰まり方です。変えた値が消えるので、キーを打ったつもりのまま先へ進んでしまいます。

キーを打つときの4つの確認点

鍵を押せているのに再生しても動かないときは、次の4つを確かめます。

Sponsored

別のアニメーションへ入っている。 パネルの選択欄が RESET のままだと、鍵は RESET という別のアニメーションへ入ります。RESET は、保存するときに各項目を戻しておく初期の姿勢を入れる、特別なアニメーションです。open を再生してもトラックが無いので、何も起きません。鍵を押す前に、選択欄が open になっているかを見ます。

選択欄がRESETのまま鍵を押すとRESETにトラックができ、再生するopenのほうは空のまま

同じ時刻に押し直している。 同じ行の同じ時刻で鍵を押すと、キーは増えずに値が上書きされます。トラックは増えたように見えても、中身は1点のままです。2点目にするには、先に針を動かします。

長さの外に残っている。 新しく作ったアニメーションの長さは1秒です。1秒の位置にキーを打ってから長さを 0.5 に縮めると、そのキーは消えずに残ったまま、範囲の外なので再生されません。長さは先に決めます。

絵だけを動かしている。 鍵は、いま選んでいるノードの項目に付きます。扉の絵である Sprite2D を選んだまま押すと、Door/Sprite2D:position の行ができます。再生すると絵だけが上へ動き、当たり判定はその場に残ります。扉ごと動かしたいなら、選ぶのは絵ではなく、絵と当たり判定をまとめている親のほうです。

Sprite2Dを選んで鍵を押すと絵だけが上がり、当たり判定は元の位置に残って通路を塞ぐ

補間と更新モード

トラックの右側には、似て見える2つの設定が並びます。

  • 補間: キーとキーのあいだをどう埋めるか。Linear は直線で結び、Nearest は次のキーに届くまで前のキーの値を保ち、Cubic は滑らかな曲線を描く。扉の位置は Linear で足りる
  • 更新モード: その値をいつ書き込むか。Continuous は毎フレーム書き込み、Discrete はキーを通過したときだけ書き込む。位置や色は Continuous、チェックボックスのようにオンとオフしかない項目は Discrete
補間はキーのあいだの埋め方、更新モードは値を書き込むタイミング。似て見えるが別の設定

Nearest は「近いほうのキーへ寄る」動きではありません。0.00秒と0.50秒にキーがあれば、0.49秒でもまだ0.00秒の値のままです。

長さの欄とループのボタンは、タイムラインの右上に並んでいます。扉のように「開いて終わり」のアニメーションは、ループをオフのままにします。オンにすると、開き切った扉が閉じた姿勢へ飛んで、また開きはじめます。

逆再生と、再生が終わったあとの状態

再生は play("open") の1行です。逆方向は play_backwards("open") を使います。

play_backwards() は、同じアニメーションを再生している途中なら、その位置から戻ります。0.2秒まで開いたところで呼べば、0.2秒から閉じていきます。終端へ移ってから戻るのは、別のアニメーションから切り替えたときと、位置が0秒のときです。

同じアニメの途中で呼ぶとその位置から戻り、別のアニメからや0秒のときは終端から戻る

再生が終わったあとの状態にも、つまずきやすいところがあります。 再生が止まると current_animation は空の文字列になります。 アニメーション名が残るのは assigned_animation のほうです。位置と長さは終端の値のままなので、「もう開き切っているか」は、再生中でないこと・assigned_animation が "open" であること・位置が長さと等しいことの3つで見ます(実践の _is_fully_open())。

これを見ずに play("open") を呼ぶと、再生は0秒からやり直しになります。開き切った扉が、いったん閉じてから開き直します。

Sponsored

実践:踏むと開く扉

ダンジョンの仕掛け扉、レースゲームのスタートゲート、脱出ゲームの隠し戸——近づくと開いて、離れると閉まる形はどれも同じです。扉が上へ64ピクセル退避して通路が空き、通り過ぎると元へ戻るところまで作ります。

① 置くもの

通路を横切る扉を、新しいシーンに1つ作ります。

  • ルートに Node2D を置いて名前を Level にし、level.gd を付ける
  • Level の子に AnimatableBody2D を置いて Door。位置 (320, 300)。Sync To Physics をオンにする
  • Door の子に Sprite2D(Texture に icon.svg・Scale を (0.5, 0.5))と CollisionShape2D(RectangleShape2D・サイズ (64, 64))を置く
  • Level の子に AnimationPlayer を置く。インスペクタの Callback Mode の中の Process を Physics にする
  • Level の子に StaticBody2D を2つ置いて WallTop(位置 (320, 236))と WallBottom(位置 (320, 364))
  • 壁2つの子に CollisionShape2D(RectangleShape2D・サイズ (640, 64))をそれぞれ置く
  • Level の子に Area2D(重なりを知らせるだけで、体は止めない範囲)を置いて Switch。位置 (320, 300)。子に CollisionShape2D(RectangleShape2D・サイズ (256, 128))
  • Level の子に CharacterBody2D を置いて Player。位置 (140, 300)。Groups ドックでグループ player(ノードに付ける名札)に入れて、player.gd を作って付ける
  • Player の子に Sprite2D(Texture に icon.svg・Scale を (0.3, 0.3))と CollisionShape2D(CircleShape2D・半径 20)を置く
通路の真ん中を扉が塞ぎ、スイッチの範囲は扉の4倍の幅で、扉の手前から向こう側までを覆う

Switch と壁は形だけなので、実行しても見えません。エディタ上部の Debug から Visible Collision Shapes をオンにしてください。

上下の壁が作る通路は y が 268 から 332 の帯で、閉じた扉がちょうどそこを塞いでいます。扉が64ピクセル上がると 204 から 268 へ移り、通路から完全に外れます。

Switch は扉より広く取ります。扉の手前だけを覆う形にすると、通路へ入った瞬間にスイッチから外れて、通り抜ける前に扉が下りてきます。広く取ったぶん、Switch には扉や壁も重なるので、体が範囲に入ったときに届く body_entered はそれらにも来ます。コードがグループでプレイヤーだけを見分けているのは、このためです。

扉を StaticBody2D ではなく AnimatableBody2D にするのは、動く扉として物を押せるようにするためです。StaticBody2D を動かしても、その動きは物を押す移動として扱われません。Sync To Physics と、AnimationPlayer の Process を Physics にそろえると、扉の移動が物理の更新と同じタイミングで行われ、押された側の動きががたつきません。

② キーを2つ打つ

AnimationPlayer を選び、下のパネルで新しいアニメーションを open という名前で作ります。最初に長さを 0.5 にして、ループはオフのままにします。

そのあと、シーンツリーで Door を選んでから次の順に進めます。Sprite2D ではなく Door を選ぶのが大事なところです。

  1. 針を 0.00 秒へ動かす
  2. インスペクタの Transform > Position が (320, 300) になっているのを確認して、右端の鍵を押す
  3. トラックを作るかを聞かれるので、Use Bezier Curves はオフ(オンにすると別の種類のトラックになる)、Create RESET Track(s) はオンのまま作成する
  4. 針を 0.50 秒へ動かす
  5. Position の y を 236 に変える(64ピクセル上)
  6. もう一度、Position の鍵を押す

Door:position という行が1本でき、0.00秒と0.50秒にキーが並んでいれば成功です。Door/Sprite2D:position になっていたら、選び直してやり直します。

Switch を選び、Signals ドックから body_entered と body_exited を Level へ接続します。

# level.gd
extends Node2D

@onready var anim: AnimationPlayer = $AnimationPlayer

func _on_switch_body_entered(body: Node2D) -> void:
	if not body.is_in_group("player"):
		return
	if _is_fully_open():
		return                             # 開き切っているのに play すると0秒へ戻る
	anim.play("open")

func _on_switch_body_exited(body: Node2D) -> void:
	if not body.is_in_group("player"):
		return
	anim.play_backwards("open")            # 途中なら、その位置から戻る

func _is_fully_open() -> bool:
	if anim.is_playing():
		return false                       # 動いている最中は開き切りではない
	if anim.assigned_animation != "open":
		return false                       # 終わると current_animation は空になる
	return is_equal_approx(anim.current_animation_position, anim.current_animation_length)   # 小数の誤差を許して比べる
# player.gd
extends CharacterBody2D

const SPEED := 300.0

func _physics_process(_delta: float) -> void:
	velocity = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") * SPEED
	move_and_slide()

③ 動かして確かめる

針を0.00秒・0.25秒・0.50秒に置くと、扉は300・268・236と上がり、開き切ると通路が空く

実行する前に、タイムラインの針を手で動かします。Door を選んだまま針を 0.25 秒に置くと、インスペクタの Position は (320, 268) です。0.00秒の 300 と0.50秒の 236 のちょうど中間で、自分では一度も打っていない数字です。あいだを補間が埋めています。300 のままなら、0.50秒のキーが無いか、補間が Nearest か更新モードが Discrete になっています。

確認できたら、針を 0.00 秒へ戻してから保存します。AnimationPlayer の Reset On Save(既定でオン)が、保存のときに RESET の値へ戻します。別の時刻を映したまま保存しても、保存されるのは閉じた位置です。

実行して、右矢印キーで右へ歩きます。スイッチの範囲に入ると扉が上がりはじめます。扉が上がり切る前にプレイヤーが届くので、少しのあいだ扉の下の角に引っかかり、スイッチに入ってから約0.4秒で下をくぐれるようになります。扉の絵だけが上がって通れないなら、キーを打ったのが Sprite2D の行です。扉の下を通り抜けてもまだスイッチの中なので、扉は開いたままです。右端まで歩いてスイッチから出ると、扉が下りてきて通路を塞ぎます。

仕上げに、スイッチの左端に少しだけ入って立ち止まり、扉が上がり切る前に左へ出ます。扉は上がったその高さから閉まりはじめ、いったん上まで飛んでから閉じることはありません。打ったのは0.00秒と0.50秒の2つのキーだけで、途中の高さはすべて補間が埋めています。

ポイントは2つです。

  • 鍵は「いま選んでいるノードの、その項目」に付く: Sprite2D を選んだまま押すと絵だけが動き、当たり判定はその場に残ります。行の名前が、動かしたいノードと一致しているかを毎回見てください
  • 止まっているアニメの名前は assigned_animation にある: current_animation が返すのは再生中の名前だけです。止まると空になるので、そこと名前を比べても一致しません

閉じ切ったときや開き切ったときに音や演出を足したくなったら、AnimationPlayerで判定と音を1本にまとめる記事 へ進んでください。

うまくいかないときは

症状原因直し方
起動した時点で扉が開いているRESET のトラックが無いまま、開いた時刻を映して保存した。または RESET に開いた姿勢が入っている選択欄を RESET にして、Door:position のキーを (320, 300) に打ち直す。RESET が無いなら、針を0.00秒へ戻してから保存する
扉を別の場所へ動かしたら、再生した瞬間に元の位置へ飛ぶキーは、親の Level から見た (320, 300) という位置そのものを記録している扉を置き直したらキーも打ち直す。扉を1つのシーンにまとめ、そのシーンの中の子の position にキーを打てば、置き場所に左右されない(ルートの position に打つと、置いた場所に関係なくその座標へ飛ぶ)
扉を複製したら、片方しか動かないトラックは Door:position のように名前で相手を指す。複製した Door2 は対象に入っていない扉ごとに AnimationPlayer を持たせる。扉を1つのシーンにして、インスタンスとして並べる

おまけ:先に知っておくと良いこと

Node2D の rotation は、そのノードの原点を中心に回ります。蝶番のように端を軸にして回したいときは、軸の位置に親のノードを置き、その子に絵をずらして置いて、親の rotation を動かします。扉の絵そのものに角度を付けると、真ん中で回ってしまいます。

扉が開いているあいだだけ当たり判定を消す作り方もあります。CollisionShape2D の Disabled にも鍵は押せます。この場合は更新モードを Discrete にして、切り替えたい時刻にだけキーを置きます。実践のように扉ごと動かせるなら、判定を触らないほうが状態が1つで済みます。

行き先が実行時まで決まらない動き、たとえば拾ったコインが飛んでいく先のようなものは、キーを打つより Tween のほうが向きます。キーは行き先が最初から決まっているときの道具です。

絵の切り替えとの役割分担は AnimatedSprite2Dとの比較、扉が開くのを見せるあいだ操作を止める組み方は カットシーン入門 にあります。

まとめ

  • 1行はインスペクタの1項目: 鍵は「この時刻の、この項目は、いまこの値」を書き込む
  • 針、値、鍵の順: 値を変えてから針を動かすと、移動先の値で上書きされる
  • 長さは先に決める: あとから縮めると、外に出たキーは残ったまま再生されない
  • 鍵は選んでいるノードに付く: 扉ごと動かすなら、絵ではなく親を選ぶ
  • play_backwards() は途中から戻る: 同じアニメーションの途中ならその位置から。止まったアニメーションの名前は assigned_animation に残る

鍵を押す前に選ぶノードで、動くものが決まります。いま動かしたいのは絵でしょうか。それとも、絵と当たり判定をまとめた入れ物のほうでしょうか。

次に読む学習パスの次の記事
アニメーション

AnimationPlayerの高度な活用

この記事を読む
Godot このセクションのノート104