game-feel について
game-feelは、手応えや反応が弱い既存のゲームメカニクスにフィードバックを加えるスキルです。画面揺れやヒットストップ、イージングなどを扱い、シミュレーションと視覚効果を分け、イベントの重要度に応じて強さを調整する方法を説明します。
主な機能
- 01画面揺れとヒットストップの設計
- 02イージングとスクワッシュ&ストレッチの適用
- 03ノックバック・フラッシュ・パーティクルの組み合わせ
- 04イベントの重要度に応じた調整
- 05GodotとUnityの例および注意点
活用シーン
- 01ヒットやアイテム取得の反応強化
- 02ジャンプやダッシュの応答性向上
- 03重要度別のイベント演出設定
- 04演出過多や入力阻害の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill game-feelインストール後、Claude Code で/game-feelを入力して読み込まれたか確認します。
同梱ファイルreferences/feedback-recipes.md
詳細
ゲームフィール(ジュース)
機能するメカニクスと、気持ちよく感じられるメカニクスの違いはフィードバックです。アクションによって引き起こされる、重ね合わせた少し誇張気味の反応です。このスキルでは、エンジンに依存しない手法――画面の揺れ、ヒットストップ、イージング、スクワッシュ&ストレッチ、ノックバック、複数のフィードバックの重ね合わせ――を取り上げ、基盤となるシミュレーションを覆い隠さずに適用する方法を説明します。既存のメカニクスに磨きをかけるものであり、メカニクス自体を実装するものではありません。
使用するタイミング
- アクション(攻撃、ジャンプ、ダッシュ、アイテム取得、死亡、ボタン押下)がメカニクスとしては正しく動作するものの、手応えが弱い、軽い、または満足感がないときに使います。反応がよく、力強い感触にしたい場合に適しています。
- 画面の揺れ、ヒットストップ/フリーズフレーム、イージングを使った動き、スクワッシュ&ストレッチ、ノックバック、フラッシュを追加したり、1つのイベントに複数のフィードバック要素を重ねたりするときに使います。
- ジュースをどの程度加えるべきか、どこから過剰なノイズになるかを判断するときに使います。
使用しない場合: 生のコントローラー計算(ジャンプの高さ、コヨーテタイム)には、ジャンルの platformer とエンジンの移動スキルを使います。カメラの追従/デッドゾーン/オービットの構図には camera-systems を使います(このスキルが扱うのは揺れの発生のみです)。ミキシング、ダッキング、アダプティブミュージックには audio-design を使います。シェーダーベースのディゾルブ/フラッシュには、shader-programming とエンジンのシェーダースキルを使います。具体的なトゥイーン/パーティクルノードの API には、エンジンのアニメーションスキル(godot-animation、unity-animation)を使います。
基本原則:フィードバックを重ね、誇張する
満足感のある攻撃ヒットでは、通常、約 100 ms 以内に5~8 個の小さな反応が同時に起きます。効果音、パーティクルの放出、短いヒットストップ、フラッシュ、ノックバック、小さな画面の揺れ、数字のポップアップなどです。それぞれの処理は軽量ですが、重ねると「衝撃」として伝わります。ごちゃごちゃさせないためのルールは 2 つです。**(1)短時間だけ誇張し、通常の状態に戻します(ジュースは一時的なもので、新しい通常状態ではありません)。(2)**イベントの重要度に合わせてジュースの強さを調整します。足音とボスの死亡を同じ扱いにはしません。
基本的なワークフロー
- イベントフックが存在することを確認します。 ジュースは、
on_hit、on_land、on_pickup、on_death、on_fireのような個別のイベントに紐づけます。メカニクスがこれらのイベントを発行しない場合は、まず追加します。 - イベントごとにフィードバック要素を選びます。 メニュー(サウンド、パーティクル、揺れ、ヒットストップ、フラッシュ、ノックバック、トゥイーン、数字のポップアップ)から選びます。まず 2~3 個から始め、効果が伝わるまで追加したら止めます。
- 動きはリニアではなく、イージングを使います。 スケール/位置/UI の変化は、イージングを指定したトゥイーンで処理します(「ポップ」にはオーバーシュート、「落ち着き」にはイーズアウト)。リニアな動きは機械的に感じられます。
- ヒットストップと揺れは衝撃を表現するために取っておきます。 これらは最も強力で、最も乱用しやすい手法です。短い時間にし、重要度に応じて強さを調整し、日常的なアクションには使いません。
- フィードバックを重要なシミュレーション処理から切り離します。 揺らすのは本体ではなく、カメラ/ビジュアルです。ヒットストップにはタイムスケールの変更またはリアルタイムの一時停止を使い、ゲームプレイロジックを停止させません。
- 重要度の段階ごとに調整します。 小/中/大のフィードバックプリセットを定義し、イベントを各段階に割り当てます。そうすれば、ゲーム全体のジュースに一貫性があり、重要度に見合ったものになります。
- 実際にプレイして確認します。 イベントを繰り返し発生させ、フィードバックが起きて通常の状態に戻ること、そして酔いや入力の妨げがないことを確認します。確認した内容を報告します(揺れは減衰しますか? ヒットストップ中も入力は受け付けられますか?)。
パターン
1. 減衰する「トラウマ」による画面の揺れ(ランダムなガタつきではなく滑らかな揺れ)
# Godot 4.7. Store trauma 0..1; shake = trauma^2 so small hits barely move, big hits punch.
# Drives a Camera2D OFFSET (the visual), never the player body. Decays every frame.
@export var decay := 1.2 # trauma lost per second
@export var max_offset := Vector2(12, 8)
@export var max_roll := 0.1 # radians
var trauma := 0.0
var _t := 0.0
func add_trauma(amount: float) -> void:
trauma = clampf(trauma + amount, 0.0, 1.0) # hits ADD; they don't reset
func _process(dt: float) -> void:
if trauma <= 0.0: return
trauma = maxf(trauma - decay * dt, 0.0)
var shake := trauma * trauma # quadratic: gentle low, sharp high
_t += dt * 30.0
# Smooth pseudo-random via sampled noise/sin, NOT rand each frame (that buzzes).
offset = Vector2(max_offset.x * shake * sin(_t * 1.7),
max_offset.y * shake * sin(_t * 2.3))
rotation = max_roll * shake * sin(_t * 1.1)
# Unity 6.3 LTS: identical model on a CinemachineCamera via CinemachineBasicMultiChannelPerlin
# (set AmplitudeGain/FrequencyGain from trauma^2) — see camera-systems.
2. ヒットストップ/フリーズフレーム(時間を短く止めて衝撃を強調する)
# Godot 4.7. Drop time scale, then restore after a REAL-TIME delay (unaffected by time_scale).
func hit_stop(duration := 0.08, scale := 0.05) -> void:
Engine.time_scale = scale
# 4th arg ignore_time_scale=true → the timer still fires while the game is frozen.
await get_tree().create_timer(duration, true, false, true).timeout
Engine.time_scale = 1.0
// Unity 6.3 LTS (C#). WaitForSecondsRealtime ignores Time.timeScale, so the timer still elapses.
IEnumerator HitStop(float duration = 0.08f, float scale = 0.05f) {
Time.timeScale = scale;
yield return new WaitForSecondsRealtime(duration);
Time.timeScale = 1f; // RIGHT: real-time wait. WRONG: WaitForSeconds (never resumes at scale 0)
}
3. イージング付きトゥイーンによるスクワッシュ&ストレッチ+オーバーシュート(「ポップ」)
# Godot 4.7. Conserve volume: stretch one axis, squash the other, then spring back with overshoot.
func pop(node: Node2D) -> void:
node.scale = Vector2(1.3, 0.7) # instant squash on the event
var tw := create_tween()
tw.tween_property(node, "scale", Vector2.ONE, 0.18) \
.set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT) # BACK = overshoots past 1, settles
# RIGHT: ease back (TRANS_BACK/ELASTIC) for life. WRONG: linear tween → mechanical, dead.
4. 重要度に応じて強さを調整するフィードバックの組み合わせ(ジュースの強さを適切に保つ)
# One call per event; the tier decides intensity so the whole game stays consistent.
func feedback(event_pos: Vector2, tier: String) -> void:
match tier:
"small": AudioBus.play("tick"); Camera.add_trauma(0.15)
"medium": AudioBus.play("hit"); Camera.add_trauma(0.4); hit_stop(0.05); spawn_particles(event_pos, 6)
"large": AudioBus.play("boom"); Camera.add_trauma(0.8); hit_stop(0.12); spawn_particles(event_pos, 30); flash_white(0.06)
注意点
- カメラオフセットではなく、プレイヤー/ボディを揺らすと、衝突判定と照準がずれます。シミュレーション対象のトランスフォームではなく、カメラ(またはビジュアル用のピボット)を揺らしてください。
- 毎フレームランダムなオフセットを加えると、ノイズのように震えます。サンプリングしたノイズや sin 波に、減衰するトラウマ値を組み合わせて揺れを制御すると、滑らかに収まり、自動的に止まります。
WaitForSecondsやスケールされたタイマーでヒットストップを行うと、再開できなくなります(タイムスケールが 0 の間はタイマーが進みません)。実時間で待機する方法(WaitForSecondsRealtimeまたは Godot のignore_time_scaleタイマー)を使ってください。- 攻撃を押し続けている間、毎フレームヒットストップを発生させると、ゲームが停止します。インパクトごとに一度だけ発生させてください。
- どこでも線形トゥイーンを使うと、ロボットのような動きになります。ほとんどの動きにはイージングを使い、オーバーシュート(BACK/ELASTIC)は「ポップ」に、イーズアウトは「落ち着き」に限定してください。
- 誇張した表現を戻さない(スケールが戻らない、揺れが減衰しない)と、それが新たな通常状態になり、フィードバックとして伝わらなくなります。演出は必ず元の状態に戻してください。
- 日常的なアクションを過剰に演出する(足音のたびに大きく揺らし、ヒットストップを入れる)と、プレイヤーに不快感を与え、本当のインパクトが目立たなくなります。重要度に合わせて調整し、「画面の揺れを軽減」「点滅を軽減」といったアクセシビリティオプションを追加してください。
- フィードバックで入力を妨げる(長いフリーズ、キャンセルできないアニメーション)と、応答性が損なわれます。演出は短く保ち、その間も入力をバッファリングできるようにしてください。
参考資料
- トラウマシェイクの計算式、イージングカーブのチートシート(ポップと落ち着きに適したイージング)、ノックバック+フラッシュ+数値ポップのレシピ、重要度別のプリセット、エンジンごとのトゥイーン/パーティクルのバインディングについては、
references/feedback-recipes.mdを参照してください。
関連スキル
camera-systems— カメラの追従/デッドゾーン/オービットを担当します。このスキルはシェイクのトラウマ値を渡すだけです。godot-animation、unity-animation— 演出に利用する具体的なトゥイーン/AnimationPlayer/パーティクルの API です。audio-design— あらゆるフィードバックの組み合わせにおけるサウンドレイヤーです。ダッキングや効果音のバリエーションも扱います。physics-tuning— ノックバックの力や、演出によって不安定になってはならないタイムステップを扱います。platformer、fps-shooter、roguelike— 一瞬一瞬の操作感を高めるジャンルです。