mcpField
P
physics-tuning

physics-tuning

github.com/gamedev-skills開発5.4k7.7k 回インストール1 日前に更新
リポジトリ

physics-tuning について

physics-tuning は、ジッター、すり抜け、不安定な動きを調べるゲーム開発向けのエンジン非依存スキルです。固定タイムステップ、描画補間、剛体設定、連続衝突検出、衝突レイヤーを扱います。

主な機能

  1. 01固定タイムステップでの物理演算
  2. 02ジッターを抑える描画補間
  3. 03質量・抵抗・重力の調整
  4. 04CCD と速度制限の適用
  5. 05衝突レイヤーとマスクの設定

活用シーン

  1. 01低フレームレート時の動きの揺れを調査
  2. 02高速物体の壁抜けを抑制
  3. 03剛体の積み重ねやジョイントを安定化
  4. 04反発と減衰の調整

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill physics-tuning

インストール後、Claude Code で/physics-tuningを入力して読み込まれたか確認します。

同梱ファイルreferences/timestep-and-ccd.md

詳細

物理演算の調整

「物理演算がおかしい」問題の多くはエンジンのバグではなく、固定タイムステップのシミュレーションと可変レートのレンダーループとの不整合、または質量/ドラッグ/CCD/レイヤー設定が未調整であることが原因です。このスキルでは、物理演算を安定させ、反応を良くするためのエンジンに依存しない調整項目を扱います。具体的な API については、godot-physics または unity-physics と併用してください。

使用する場面

  • 動きがガタつく、オブジェクトが壁をすり抜ける(トンネリング)、積み重ねたオブジェクトが吹き飛ぶ、または動きが浮つく/貼り付く/遅れるように感じるときに使用します。
  • 固定(物理)ステップとレンダーフレームのどちらで処理するか、またそれらの間をどう補間するかを判断するときに使用します。
  • 重力、質量、ドラッグ、反発係数、ソルバーの反復回数、スリープ、衝突レイヤー/マスクを調整するときに使用します。

使用しない場面: エンジン固有の物理ノード/コンポーネントや衝突コールバックについては、godot-physics または unity-physics を使用してください。移動の判断(ジャンプするタイミング、AI のステアリング)には、input-systems と game-ai を使用してください。コヨーテタイムやジャンプバッファリングなど、プラットフォーマーのジャンプの操作感に関する詳細は入力/コントローラーの領域です。input-systems と platformer ジャンルを参照してください。

基本的なワークフロー

  1. 物理演算を固定タイムステップで実行します。 一定のレート(例:50~60 Hz)でシミュレーションします。固定の dt により、シミュレーションは決定論的に近くなり、安定します。可変の dt では、積分や衝突判定が一貫しなくなります。
  2. 物理演算の処理はレンダーフレームではなく、物理コールバック内に配置します。 力/速度の適用と衝突情報の読み取りは、そのステップの dt を使って固定ステップ(FixedUpdate/_physics_process)で行います。
  3. 物理ティックの間を補間してレンダリングします。 レンダーフレームレートと物理レートは異なるため、変換情報を最新の物理状態に向けて滑らかに補間するか、エンジンの Rigidbody 補間を有効にして、目に見えるカクつきをなくします。
  4. シーンではなく、剛体を調整します。 相対的な重さを質量で、減衰をドラッグで設定し、オブジェクトごとに重力スケールを調整します。また、マテリアルで反発係数/摩擦を設定します。
  5. 小さく高速な剛体では CCD を使ってトンネリングを防ぎ、最大速度に上限を設けます。
  6. ソルバーの反復回数を増やし、妥当な質量比にして、静止中の剛体をスリープさせることで、積み重ねやジョイントを安定させます。
  7. 操作感を確認し、ストレステストを行います。 低フレームレートと高フレームレートの両方でプレイし、高速なオブジェクトを薄い壁にぶつけ、剛体を積み重ねて押します。観察したことを報告します。

パターン

1. シミュレーションには固定タイムステップ、滑らかさにはレンダー補間
# Physics callback: runs at the FIXED rate. Use its dt for all integration.
func _physics_process(dt):                  # Unity: void FixedUpdate()
    velocity += gravity * dt                # integrate with the FIXED dt
    move_and_slide()                        # engine resolves collisions this step
    _prev_pos = _curr_pos; _curr_pos = global_position   # record for interpolation

# Render frame: runs as fast as the display. Interpolate between physics states.
func _process(_frame_dt):                   # Unity: void Update()
    var alpha = Engine.get_physics_interpolation_fraction()  # 0..1 within the tick
    visual.global_position = _prev_pos.lerp(_curr_pos, alpha)
# RIGHT: integrate in the fixed step, render via interpolation.
# WRONG: applying forces in _process/Update with frame dt — speed and collisions
# then depend on frame rate and jitter under load.

ほとんどのエンジンには、この機能が組み込まれています(Godot の physics_interpolation/Rigidbody interpolate、Unity の Rigidbody.interpolation = Interpolate)。独自に実装する前に、組み込み機能を優先してください。

2. トンネリングを防ぐ:CCD と速度上限
# Fast, small bodies skip past thin colliders between ticks. Two fixes:
body.continuous_cd = true            # RigidBody3D bool (RigidBody2D: CCD_MODE_* enum). Unity: rb.collisionDetectionMode = Continuous
# Cap velocity so a single step can't move more than ~one collider thickness.
const MAX_SPEED := 40.0
if velocity.length() > MAX_SPEED:
    velocity = velocity.normalized() * MAX_SPEED
# Rule of thumb: max_distance_per_step (= speed / physics_hz) should be < the
# thinnest wall. Raise physics_hz or enable CCD when that fails.
3. 剛体の調整:質量、ドラッグ、重力スケール、マテリアル
# Mass is RELATIVE weight in collisions; it does NOT change fall speed (gravity
# accelerates all masses equally). Use drag and gravity_scale to shape feel.
body.mass = 2.0                      # heavier pushes lighter in collisions
body.linear_damp = 0.5               # air drag: higher = stops sooner (Unity: drag)
body.gravity_scale = 1.5             # per-object gravity multiplier (snappier fall)
# Bounce/slide come from the physics material, not code:
material.bounce = 0.2                # restitution 0..1 (Unity: bounciness)
material.friction = 0.8              # surface grip
4. 衝突レイヤーとマスク(どのオブジェクト同士が衝突するか)
# A body is ON its layer(s) and SCANS the layers in its mask. Both directions of a
# pair must be configured for them to interact.
player.collision_layer = LAYER_PLAYER
player.collision_mask  = LAYER_WORLD | LAYER_ENEMY     # player detects world+enemies
pickup.collision_layer = LAYER_PICKUP
pickup.collision_mask  = LAYER_PLAYER                  # pickup only reacts to player
# Unity equivalent: assign GameObject layers and edit the Physics collision matrix
# (or Physics.IgnoreLayerCollision). Keep a named layer constant table, not magic numbers.

よくある落とし穴

  • レンダリングフレーム内で力や移動を適用する(Update/_process)と、動作がフレームレートに依存します。性能の高い PC ほど動作が速くなり、衝突も不安定になります。シミュレーションは固定ステップで行ってください。
  • 固定ステップでも目に見える揺れがある場合は、通常、レンダリング補間がありません。物理演算のレートとディスプレイのリフレッシュレートが干渉しています。補間を有効にしてください。
  • 薄い壁をすり抜ける(トンネリング):離散的な衝突判定では、高速で移動する物体を検出できないことがあります。CCD を有効にする、速度に上限を設ける、壁を厚くする、または物理演算のレートを上げてください。
  • 重い物体ほど速く落下すると考えること。 重力は加速度です。質量が影響するのは衝突応答であり、落下速度ではありません。物体の感触は gravity_scale/ドラッグで調整してください。
  • 積み上げた物体が弾ける/ジョイントが揺れる:質量比が極端すぎるか、ソルバーの反復回数が少なすぎます。質量比を適度に保ち、反復回数を増やしてください。
  • 物体がいつまでも静止しないと CPU を消費し、細かく震えます。静止した物体にはスリープを有効にし、適切なしきい値を設定してください。
  • レイヤー設定が一方向だけになっている:A のマスクには B が含まれているのに、B のマスクには A が含まれていません。検出や衝突には両側の設定が必要な場合があります。全体のマトリクスを確認してください。
  • dt の大きなスパイク(ロード時の引っ掛かり、ブレークポイント)は積分処理を破綻させます。停止が発生してもすべての物体が飛び出さないよう、最大物理ステップ数/サブステップ数を制限してください。

リファレンス

  • references/timestep-and-ccd.md — 固定タイムステップのアキュムレーターループ、補間の計算式、サブステップ、CCD モード、ソルバー/反復回数の調整、スリープ、安定性チェックリスト。

関連スキル

  • godot-physics、unity-physics — 具体的な剛体、コライダー、コールバック。
  • input-systems — 応答性の高い操作、ジャンプバッファリング、コヨーテタイム。
  • game-ai — 物理演算のステップと一致させる必要があるエージェントの移動。
  • platformer、fps-shooter — 操作感がこうした調整に左右されるジャンル。

コメント