【Godot】Tweenで実現する滑らかなアニメーション

作成: 2025-12-06最終更新: 2026-07-08

UI演出、ダメージ点滅、HPバー、動く床など、時間経過を伴う値の変化を create_tween() で手軽に実装する方法を、イージング・連結/並列・await まで実践的に解説します。

敵に当たった瞬間にキャラがカクッと点滅する、メニューがパッと切り替わる、HPバーの数値がいきなり飛ぶ——動いてはいるけれど、どこか安っぽく見える。その差を生んでいるのが「滑らかさ」です。

こうした「時間をかけた値の変化」を、Godotでは Tween がひとことで書けます。create_tween() を呼んで「どのノードの・どのプロパティを・何秒かけて・いくつまで変えるか」を予約するだけ。UIのスライドインも、ダメージ点滅も、HPバーのじわ減りも、すべて同じ仕組みで作れます。

青い球体が滑らかなカーブを描きながら残像を残して移動していく、なめらかなアニメーションのイメージ

この記事でわかること

  • create_tween()tween_property() の基本形(撃ちっぱなしで動く手軽さ)
  • set_trans / set_ease による イージング(緩急) の付け方
  • アニメーションの 連結(順番)と並列(同時)await での完了待ち
  • kill() での競合防止と、AnimationPlayer との使い分け

Sponsored

Tweenの基本:1行で始める滑らかな動き

Tweenの考え方は、「 あるノードの・あるプロパティを・指定した時間で・目標の値まで滑らかに変化させる 」という、とてもシンプルなものです。

Tweenの基本の考え方の図。開始位置にある球体が、tween_propertyによって指定した時間をかけて、なめらかなカーブを描きながら目標位置まで変化する

Godot 4では create_tween() でTweenを作り、tween_property() でアニメーションを予約します。

func _ready() -> void:
    # 1. Tweenオブジェクトを生成する
    var tween := create_tween()

    # 2. アニメーションを予約する
    #    $Sprite2D の position を、1秒かけて (500, 300) まで動かす
    tween.tween_property($Sprite2D, "position", Vector2(500, 300), 1.0)

create_tween() で作ったTweenは、予約したアニメーションがすべて終わると 自動的に停止してメモリから解放 されます。この「撃ちっぱなし(Fire and Forget)」で使える手軽さが、Tweenの一番の魅力です。動かしたいときに1本作って予約するだけで、後片付けを気にせず使えます。

注意: Tweenを作ったノードが queue_free() で消えると、そのTweenも一緒に止まります。ノードの寿命を超えて演出を続けたい場合(例: 敵が消えたあとも爆発エフェクトを最後まで見せたい)は、演出を別の生き残るノード側で作るか、Autoloadで管理することを検討します。

Sponsored

イージングで「緩急」を付ける

ただ一定の速度で動かすだけでは、まだ機械的な印象です。動きの「加速・減速」を決めるのが イージング で、set_trans()(変化のカーブの種類)と set_ease()(カーブのどこで緩急を効かせるか)の2つで指定します。

イージングの違いの比較図。一定は残像が等間隔に並び直線的に変化する。EASE_OUTは始めは間隔が広く終わりに向かって間隔が詰まり、終わりで減速する

同じ「0.5秒で移動」でも、終わりに向かってスッと減速する(EASE_OUT)だけで、ぐっと上質な動きになります。

func show_menu() -> void:
    var menu := $MenuPanel
    menu.visible = true

    # いったん画面右の外側へ置く
    var viewport_width := get_viewport_rect().size.x
    menu.position.x = viewport_width

    var tween := create_tween()
    # TRANS_SINE = サインカーブでなめらかに / EASE_OUT = 終わりで減速
    tween.tween_property(menu, "position:x", viewport_width - menu.size.x, 0.5) \
        .set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)

position:x のように プロパティ名の後ろに :x を付ける と、その成分だけをアニメーションできます。よく使うのは、入ってくるUIは EASE_OUT(勢いよく入って終わりで止まる)、消えるUIは EASE_IN(じわっと加速して去る)です。迷ったらまず TRANS_SINE + EASE_OUT を試すと、たいていの演出が自然になります。

Sponsored

実践的なコードレシピ集

レシピ1:HPバーの滑らかな増減

ダメージや回復を即座に反映するより、HPバーがじわっと動くほうが、プレイヤーは変化を直感的に捉えられます。ProgressBarvalue をTweenで動かすだけです。

HPバーの値をTweenでなめらかに減らす図。青く満たされたバーが、tween_property(value)によって目標位置まで左へじわっと縮んでいく
@onready var hp_bar: ProgressBar = $ProgressBar

func update_health_smoothly(new_health: float) -> void:
    var tween := create_tween()
    # value を 0.4秒かけて new_health へ。両端がなめらかになるEASE_IN_OUT
    tween.tween_property(hp_bar, "value", new_health, 0.4) \
        .set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN_OUT)

レシピ2:被ダメージの点滅(無敵時間の表現)

ダメージを受けた直後の無敵時間などを、点滅で見せる定番の演出です。modulate のアルファ値(透明度)を往復させ、set_loops() で回数を指定します。

点滅の仕組みの図。キャラクターの透明度が濃い・薄いを交互にくり返し、その透明度の変化が波形グラフで示される。modulate:aを上下させることで無敵時間の点滅を表す
func start_invincibility_flicker() -> void:
    # 一連の点滅を5回くり返す
    var tween := create_tween().set_loops(5)
    tween.tween_property(self, "modulate:a", 0.3, 0.1)  # 半透明にする
    tween.tween_property(self, "modulate:a", 1.0, 0.1)  # 元に戻す

被弾で一瞬だけ白く光らせたい場合は、色そのものを変える方法が向いています(modulateによるホワイトフラッシュ で解説)。また、動く床やリフトのように「往復し続けるギミック」も、set_loops()(引数なしで無限ループ)と組み合わせれば同じ要領で作れます。

Sponsored

連結・並列・awaitで自在に操る

複数の動きを組み合わせるときは、「順番に」動かすか「同時に」動かすかを選べます。

連結と並列の違いの図。連結(シーケンス)はA・B・Cのバーが時間軸上で順番に並ぶ。並列(parallel)はA・B・Cのバーがすべて同じ位置からスタートして同時に走る
  • 連結(シーケンス)tween_property() を続けて書くと、上から順番に実行されます。
  • 並列(パラレル) :間に parallel() を挟むと、その予約は直前のものと 同時に 始まります。
func complex_animation() -> void:
    var tween := create_tween()
    var sprite := $Sprite2D

    # 1. まず1秒かけて右へ移動
    tween.tween_property(sprite, "position:x", 500.0, 1.0)

    # 2. 次は「下に移動」と「45度回転」を同時に行う(parallelで並列化)
    tween.parallel().tween_property(sprite, "position:y", 300.0, 0.5)
    tween.parallel().tween_property(sprite, "rotation_degrees", 45.0, 0.5)

    # 3. 0.5秒だけ待つ
    tween.tween_interval(0.5)

    # 4. 最後に0.3秒でフェードアウト
    tween.tween_property(sprite, "modulate:a", 0.0, 0.3)

アニメーションの完了を待つ await

「演出が終わってから次に進みたい」ときは、await とTweenの finished シグナルを組み合わせます。シグナルにコールバックを繋ぐより、処理の流れが直線的で読みやすくなります(await 自体の仕組みは awaitとコルーチンの基礎 参照)。

func play_and_destroy() -> void:
    var tween := create_tween()
    tween.tween_property(self, "scale", Vector2.ZERO, 0.5)  # 縮小して消す

    await tween.finished  # このTweenが終わるまでここで待つ

    queue_free()  # 縮小しきってから安全に削除
Sponsored

よくある間違いとベストプラクティス

よくある間違いベストプラクティス
_process() 内で毎フレーム create_tween() を呼ぶTweenは 開始したいときに一度だけ 作る。毎フレームの追従は lerp() など別手段を使う
前のTweenを止めずに新しいTweenを始め、動きが競合する新しく始める前に、前のTweenを kill() で止める(下記参照)
finished に処理をたくさん繋いで複雑化するawait tween.finished で非同期関数として直線的に書く
何でもTweenで作ろうとする複数ノード・多トラックの複雑な演出は AnimationPlayer の方が向く

Tweenの競合を防ぐ kill()

たとえば「クリックした地点へスッと動く」処理で、動いている途中に次のクリックが来ると、古いTweenと新しいTweenが同じ position を奪い合ってガクガクします。開始前に前のTweenを片付ければ防げます。

Tweenの競合とkill()の図。競合では古いTweenと新しいTweenが同じキャラクターを綱引きしてガクガクする。kill()で古いTweenを止めると、新しいTweenだけがキャラクターをなめらかに目標へ動かす
var current_tween: Tween

func animate_to(target_position: Vector2) -> void:
    # 実行中のTweenがあれば止める
    if current_tween and current_tween.is_valid():
        current_tween.kill()

    current_tween = create_tween()
    current_tween.tween_property(self, "position", target_position, 0.5)
Sponsored

TweenとAnimationPlayerの使い分け

どちらもアニメーションの道具ですが、得意分野が違います。

TweenとAnimationPlayerの使い分けの比較図。Tweenはコードの波かっこアイコンで「コードで生成」「動的・単発」、AnimationPlayerはキーフレームの並ぶタイムラインアイコンで「タイムラインで編集」「作り込み・再生」
比較項目Tween (create_tween)AnimationPlayer
得意なことコードで作る動的な演出、UI、単純な値の変化事前に作り込む複雑なシーケンス、カットシーン
セットアップ簡単(コードで完結)やや手間(エディタでキーフレーム設定)
柔軟性高い(実行時の値で自由に生成)低め(作ったものを再生するのが基本)
視覚的な編集不可得意(タイムラインで編集・プレビュー)

ざっくり言えば、 実行時に値が決まる単発の演出はTween、作り込んだ動きを繰り返し再生するならAnimationPlayer です。両者の詳しい比較や、スプライトアニメとの関係は AnimatedSprite2DとAnimationPlayerの使い分けAnimationPlayerの高度な活用 で扱っています。

実践:ダメージ数字のポップアップを組む

ここまでの「予約」「イージング」「並列」「await」を、ひとつの演出に落とし込みましょう。題材は、多くのゲームで見る ダメージ数字のポップアップ です。

  • アクションRPG :敵に当てると頭上に「120」がポンッと出て、上に浮きながら消える
  • シューティング :撃破時に加点スコアが飛び出す
  • パズル :消したブロック数やコンボ数がふわっと表示される

どれも動きは同じで、「 出た瞬間に少し拡大 → 上に浮きながら薄くなる → 消える 」という一生をたどります。この「浮く」と「薄くなる」を 同時に(並列)行い、終わったら await で待って自分を消す、というのがきれいな作り方です。

ダメージ数字ポップアップの一生を示す3コマ図。出現でスライムの頭上に120が出て、浮上+フェードで120が上へ移動し薄くなり(parallel)、消滅で数字が消える(await finished)

数字を表示する Label に、次のスクリプトを付けたシーン(damage_number.tscn)を用意します。

# damage_number.gd
extends Label

func popup(amount: int) -> void:
    text = str(amount)

    var tween := create_tween()

    # 1. 出た瞬間にポンッと拡大(小さく出てから通常サイズへ弾む)
    scale = Vector2.ZERO
    tween.tween_property(self, "scale", Vector2.ONE, 0.15) \
        .set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)

    # 2. 「上に浮く」と「薄くなる」を同時に進める(parallelで並列化)
    tween.parallel().tween_property(self, "position:y", position.y - 40.0, 0.5)
    tween.parallel().tween_property(self, "modulate:a", 0.0, 0.5)

    await tween.finished  # 浮ききって消えるまで待つ
    queue_free()          # 演出が終わってから後始末

呼び出す側(敵など)は、数字シーンを生成して popup() を呼ぶだけです。

const DAMAGE_NUMBER := preload("res://damage_number.tscn")

func take_damage(amount: int) -> void:
    hp -= amount

    var number := DAMAGE_NUMBER.instantiate()
    # 敵の子にしない。現在のシーン直下に置く(敵が先に消えても数字は残る)
    get_tree().current_scene.add_child(number)
    number.global_position = global_position + Vector2(0, -20)
    number.popup(amount)

ポイントは2つです。

  • 「浮く」と「消える」を並列にするparallel() で同時に動かすことで、上へ流れながらフェードする、あの自然な動きになります。順番に書くと「浮いてから」「消える」の二段階になり、もたついて見えます。
  • await してから queue_free() :演出が終わる前に消すと、数字が途中で"パッ"と消えて台無しです。await tween.finished で最後まで見せてから片付けます。数字ノードを敵の子にしない(現在のシーン直下に置く)のも、敵が先に倒れても数字を残すためのコツです。

同じ型で、コインの取得(跳ねて消える)、実績解除のトースト(横からスライドして数秒後に引っ込む)など、多くの単発演出を作れます。

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

Tweenで一通り動かせるようになったら、次はこのあたりが視野に入ります。今は「そういう手がある」と知っておくだけで十分です。

  • 値以外も動かせるtween_method() を使うと、プロパティではなく 自作の関数 を毎フレーム呼びながら値を渡せます。シェーダーのパラメータ更新や、複数の値をまとめて反映したいときに便利です。
  • カーブを自分で描きたいTRANS_* の種類で足りないときは、AnimationPlayer のトラックに Curve を割り当てると、手描きの緩急を再現できます(AnimationPlayerの高度な活用 参照)。
  • 途中に処理を挟みたいtween_callback(関数) を予約に混ぜると、「移動が終わった瞬間に効果音を鳴らす」のような処理を、シーケンスの途中に差し込めます。

まとめ

Godot 4の Tween は、コードだけで手軽に、それでいてパワフルに演出を作れる道具です。

  • 基本create_tween()tween_property() で「プロパティを・時間で・目標値へ」。撃ちっぱなしで自動解放される
  • 緩急set_trans / set_ease でイージングを付けるだけで、動きが一気に上質になる
  • 組み立て :連結は順番に、parallel() は同時に。await tween.finished で完了を待つ
  • 競合対策 :動きが衝突しそうなら、始める前に kill() で前のTweenを止める

まずはHPバーやUIのスライドインなど、身近な1プロパティの演出に create_tween() を足してみてください。それだけで、ゲームの手触りははっきり変わります。次は、作り込んだ動きを繰り返し再生する AnimationPlayerの高度な活用 を押さえると、演出の引き出しがぐっと増えます。