敵に当たった瞬間にキャラがカクッと点滅する、メニューがパッと切り替わる、HPバーの数値がいきなり飛ぶ——動いてはいるけれど、どこか安っぽく見える。その差を生んでいるのが「滑らかさ」です。
こうした「時間をかけた値の変化」を、Godotでは Tween がひとことで書けます。create_tween() を呼んで「どのノードの・どのプロパティを・何秒かけて・いくつ まで変えるか」を予約するだけ。UIのスライドインも、ダメージ点滅も、HPバーのじわ減りも、すべて同じ仕組みで作れます。
この記事でわかること
create_tween()とtween_property()の基本形(撃ちっぱなしで動く手軽さ)set_trans/set_easeによる イージング(緩急) の付け方- アニメーションの 連結(順番)と並列(同時)、
awaitでの完了待ちkill()での競合防止と、AnimationPlayerとの使い分け
Tweenの基本:1行で始める滑らかな動き
Tweenの考え方は、「 あるノードの・あるプロパティを・指定した時間で・目標の値まで滑らかに変化させる 」という、とてもシンプルなものです。

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

同じ「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 を試すと、たいていの演出が自然になります。
実践的なコードレシピ集
レシピ1:HPバーの滑らかな増減
ダメージや回復を即座に反映するより、HPバーがじわっと動くほうが、プレイヤーは変化を直感的に捉えられます。ProgressBar の value をTweenで動かすだけです。

@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() で回数を指定します。

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()(引数なしで無限ループ)と組み合わせれば同じ要領で作れます。
連結・並列・awaitで自在に操る
複数の動きを組み合わせるときは、「順番に」動かすか「同時に」動かすかを選べます。

- 連結(シーケンス) :
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() # 縮小しきってから安全に削除
よくある間違いとベストプラクティス
| よくある間違い | ベストプラクティス |
|---|---|
_process() 内で毎フレーム create_tween() を呼ぶ | Tweenは 開始したいときに一度だけ 作る。毎フレームの追従は lerp() など別手段を使う |
| 前のTweenを止めずに新しいTweenを始め、動きが競合する | 新しく始める前に、前のTweenを kill() で止める(下記参照) |
finished に処理をたくさん繋いで複雑化する | await tween.finished で非同期関数として直線的に書く |
| 何でもTweenで作ろうとする | 複数ノード・多トラックの複雑な演出は AnimationPlayer の方が向く |
Tweenの競合を防ぐ kill()
たとえば「クリックした地点へスッと動く」処理で、動いている途中に次のクリックが来ると、古いTweenと新しいTweenが同じ position を奪い合ってガクガクします。開始前に前の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)
TweenとAnimationPlayerの使い分け
どちらもアニメーションの道具ですが、得意分野が違います。

| 比較項目 | Tween (create_tween) | AnimationPlayer |
|---|---|---|
| 得意なこと | コードで作る動的な演出、UI、単純な値の変化 | 事前に作り込む複雑なシーケンス、カットシーン |
| セットアップ | 簡単(コードで完結) | やや手間(エディタでキーフレーム設定) |
| 柔軟性 | 高い(実行時の値で自由に生成) | 低め(作ったものを再生するのが基本) |
| 視覚的な編集 | 不可 | 得意(タイムラインで編集・プレビュー) |
ざっくり言えば、 実行時に値が決まる単発の演出はTween、作り込んだ動きを繰り返し再生するならAnimationPlayer です。両者の詳しい比較や、スプライトアニメとの関係は AnimatedSprite2DとAnimationPlayerの使い分け と AnimationPlayerの高度な活用 で扱っています。
実践:ダメージ数字のポップアップを組む
ここまでの「予約」「イージング」「並列」「await」を、ひとつの演出に落とし込みましょう。題材は、多くのゲームで見る ダメージ数字のポップアップ です。
- アクションRPG :敵に当てると頭上に「120」がポンッと出て、上に浮きながら消える
- シューティング :撃破時に加点スコアが飛び出す
- パズル :消したブロック数やコンボ数がふわっと表示される
どれも動きは同じで、「 出た瞬間に少し拡大 → 上に浮きながら薄くなる → 消える 」という一生をたどります。この「浮く」と「薄くなる」を 同時に(並列)行い、終わったら await で待って自分を消す、というのがきれいな作り方です。

数字を表示する 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の高度な活用 を押さえると、演出の引き出しがぐっと増えます。