mcpField
U
unity-physics

unity-physics

github.com/nice-wolf-studio開発4071 回インストール7 週間前に更新
リポジトリ

unity-physics について

Unity開発者向けの物理リファレンススキルです。3D・2D物理、Rigidbody、Collider、クエリ、ジョイント、一般的な実装パターンを解説します。

主な機能

  1. 013D・2D物理の概要
  2. 02Rigidbodyの設定と力の適用
  3. 03Collider、トリガー、コールバック
  4. 04レイキャスト、キャスト、重なり判定
  5. 05ジョイントの種類と用途

活用シーン

  1. 01Rigidbodyによる移動方法の選択
  2. 02トリガーイベントが発生しない原因の調査
  3. 03高速オブジェクトの衝突検出設定
  4. 04非アロケートクエリによるGC削減

インストール

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

$npx skills add https://github.com/nice-wolf-studio/unity-claude-skills --skill unity-physics

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
character-controller.md
physics2d-api.md
physics3d-api.md

詳細

Unity の物理

物理システムの概要

Unity では、プロジェクトのニーズに応じて異なる物理エンジンを統合できます。

  • 3D 物理(PhysX):3D のオブジェクト指向プロジェクト向けの Nvidia PhysX エンジン統合
  • 2D 物理(Box2D):専用コンポーネントを備えた、最適化済みの 2D 物理システム
  • どちらのシステムも、重力、衝突、力、拘束をシミュレートします
物理演算のタイミング

物理演算は、レンダリングのフレームレートとは別に、FixedUpdate を通じて固定タイムステップで実行されます。

void FixedUpdate()
{
    // All physics code belongs here, not in Update()
    rb.AddForce(Vector3.forward * speed);
}

タイミングに関する主なルール:

  • FixedUpdate は固定間隔(デフォルトでは 0.02s/50Hz)で実行されます
  • 1 フレーム内で FixedUpdate が複数回実行されたり、まったく実行されなかったりする場合があります
  • Time.fixedDeltaTime で間隔を制御します
  • 入力には Update、物理的な力には FixedUpdate を使用します
シミュレーションモード

Physics.simulationMode で、物理エンジンがステップを実行するタイミングを制御します。

  • FixedUpdate(デフォルト):固定タイムステップごとに自動的にシミュレーションを実行します
  • Update:フレームごとに 1 回シミュレーションを実行します
  • Script:Physics.Simulate() を使って手動で制御します

Rigidbody の設定

Rigidbody コンポーネントを追加すると、GameObject が物理エンジンの制御下に置かれます。剛体は物理的な力を受けても変形したり、形状が変わったりしません。

主なプロパティ
プロパティ説明デフォルト
mass質量(kg)。力の相互作用に影響します1
linearDamping線速度に対する抵抗0
angularDamping角速度に対する抵抗0.05
useGravityこの剛体に重力を適用するかどうかtrue
isKinematictrue の場合、物理的な力による制御を受けませんfalse
interpolation物理ステップ間の視覚的な揺れを滑らかにしますNone
collisionDetectionMode衝突検出に使用するアルゴリズムDiscrete
移動方法
Rigidbody rb = GetComponent<Rigidbody>();

// Apply continuous force (call in FixedUpdate)
rb.AddForce(Vector3.forward * 10f);
rb.AddForce(Vector3.up * 5f, ForceMode.Impulse);

// Apply torque
rb.AddTorque(Vector3.up * 2f);

// Apply force at a world position (creates both force and torque)
rb.AddForceAtPosition(Vector3.forward * 10f, hitPoint);

// Kinematic movement (use for isKinematic=true bodies)
rb.MovePosition(rb.position + direction * speed * Time.fixedDeltaTime);
rb.MoveRotation(targetRotation);
ForceMode のオプション
モード説明
ForceMode.Force継続的な力。質量を考慮します(デフォルト)
ForceMode.Acceleration継続的な力。質量を無視します
ForceMode.Impulse瞬間的な力。質量を考慮します
ForceMode.VelocityChange瞬間的な力。質量を無視します
スリープ状態

Rigidbody のエネルギーがスリープしきい値を下回ると、物理エンジンはその計算を停止します。rb.Sleep() と rb.WakeUp() を使って手動で制御できます。

スケールに関する警告

Unity では、ワールド空間の 1 単位を 1 メートルとみなします。スケールが不適切だと、現実離れした物理挙動になります。GameObject は現実的な比率に保ってください。


コライダーとトリガー

コライダーは、GameObject の物理的な境界を定義する不可視の形状です。視覚的なメッシュと一致させる必要はありません。

コライダーの分類
分類説明
静的コライダーコライダーのみで、Rigidbody はありません。壁や床など、動かないジオメトリに使用します。
動的 Rigidbody コライダーコライダーと Rigidbody(isKinematic=false)を組み合わせます。完全にシミュレートされます。
キネマティック Rigidbody コライダーコライダーと Rigidbody(isKinematic=true)を組み合わせます。スクリプトで移動させます。
コライダーの形状
  • プリミティブ:BoxCollider、SphereCollider、CapsuleCollider。効率的で、自動的にスケールされます
  • 複合:複雑な形状を作るために、子 GameObject に複数のプリミティブを配置します
  • MeshCollider:メッシュの形状と正確に一致します。負荷が高いため、必要な場合にのみ使用します
  • WheelCollider:レイキャストベースで、車両の物理演算機能が組み込まれています
  • TerrainCollider:地形の高さマップに一致します
トリガーコライダー

トリガーは、物理的な衝突応答を伴わずに、重なり合うコライダーを検出します。

// Set via Inspector: Collider > Is Trigger = true
// Or via script:
GetComponent<BoxCollider>().isTrigger = true;

トリガーイベントの要件:

  • 少なくとも 1 つの GameObject に Rigidbody が必要です
  • コライダーで isTrigger を有効にする必要があります
  • 重なり合う各ペアを個別に検出するには、それぞれに Rigidbody が必要です
物理マテリアル

コライダーは PhysicsMaterial に対応しており、表面の相互作用に使う摩擦や弾性を調整できます。


レイキャスト

レイキャストは、シーン内のコライダーを検出するために不可視のレイを投射します。

Physics.Raycast
// Basic: check if anything is ahead
Vector3 fwd = transform.TransformDirection(Vector3.forward);
if (Physics.Raycast(transform.position, fwd, 10))
    Debug.Log("Something ahead!");

// With hit info
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, 100.0f))
    Debug.Log("Distance to ground: " + hit.distance);

// With layer mask
int layerMask = 1 << LayerMask.NameToLayer("Enemies");
if (Physics.Raycast(origin, direction, out hit, maxDist, layerMask))
    Debug.Log("Hit enemy: " + hit.collider.gameObject.name);

// Mouse-to-world raycast
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
if (Physics.Raycast(ray, out hit, 100))
    Debug.DrawLine(ray.origin, hit.point);
RaycastHit のプロパティ
プロパティ型説明
pointVector3ワールド空間でのヒット位置
normalVector3ヒット位置における面の法線
distancefloatレイの始点からの距離
colliderColliderヒットした Collider
transformTransformヒットしたオブジェクトの Transform
その他の Cast メソッド
メソッド説明
Physics.RaycastAll()レイ上にあるすべての交差を返します
Physics.RaycastNonAlloc()事前に割り当てたバッファーを埋めます(GC 割り当てなし)
Physics.SphereCast()球を指定した方向にスイープします
Physics.BoxCast()ボックスを指定した方向にスイープします
Physics.CapsuleCast()カプセルを指定した方向にスイープします
Physics.Linecast()2 点間の Collider を確認します
Overlap クエリ(方向なし、領域チェック)
メソッド説明
Physics.OverlapSphere()球の範囲内にあるすべての Collider を検索します
Physics.OverlapBox()ボックスの範囲内にあるすべての Collider を検索します
Physics.OverlapCapsule()カプセルの範囲内にあるすべての Collider を検索します
Physics.CheckSphere()球と重なる Collider があれば true を返します
Physics.CheckBox()ボックスと重なる Collider があれば true を返します
Physics.CheckCapsule()カプセルと重なる Collider があれば true を返します
QueryTriggerInteraction

Cast/Overlap で Trigger Collider を検出するかどうかを制御します。

  • QueryTriggerInteraction.UseGlobal -- Physics.queriesHitTriggers を使用します
  • QueryTriggerInteraction.Collide -- 常に Trigger を検出します
  • QueryTriggerInteraction.Ignore -- Trigger を検出しません

衝突検出

衝突検出モード
モード説明使用例
Discrete各物理ステップの終了時に衝突を確認します。効率に優れています。ほとんどのオブジェクトのデフォルト
Continuousステップ全体を通して衝突を確認します。トンネリングを防ぎます。静的なジオメトリに衝突する高速オブジェクト
Continuous Dynamic静的および動的な Collider の両方に対して連続検出します高速オブジェクト同士の衝突
Continuous Speculative推測的接触を使用した予測的な CCDキネマティックボディ、一般的な CCD
衝突コールバック
void OnCollisionEnter(Collision other) {  // First frame of contact
    if (other.gameObject.CompareTag("Player"))
        Debug.Log("Player hit this object");
}
void OnCollisionStay(Collision other) { }  // Every physics frame while touching
void OnCollisionExit(Collision other) { }  // Contact ended
Trigger コールバック
void OnTriggerEnter(Collider other) {  // Entered trigger volume
    if (other.CompareTag("Player"))
        Debug.Log("Player entered trigger zone");
}
void OnTriggerStay(Collider other) {   // Each frame inside trigger
    other.attachedRigidbody?.AddForce(Vector3.up * 12f, ForceMode.Acceleration);
}
void OnTriggerExit(Collider other) { } // Left trigger volume
衝突マトリックス
ペア衝突イベントTrigger イベント
Static + Dynamicはい--
Static + Kinematicいいえ--
Static + Staticいいえ--
Dynamic + Dynamicはい--
Dynamic + Kinematicはい--
Kinematic + Kinematicいいえ--
Trigger + Dynamic/Kinematic--はい
Static Trigger + Dynamic/Kinematic--はい

衝突イベントには、少なくとも 1 つの動的(非キネマティック)Rigidbody が必要です。物理エンジンが力を適用するのは、Rigidbody または ArticulationBody コンポーネントを持つ GameObject のみです。


ジョイント

ジョイントは Rigidbody コンポーネント同士、または Rigidbody コンポーネントと空間内の固定点を接続します。

ジョイントの種類説明使用例
FixedJoint2 つのボディを固定します(ばねとして実装)オブジェクトの取り付け、破断可能な接続
HingeJoint単一軸を中心とした回転ドア、振り子、チェーン
SpringJoint距離を維持する弾性接続バンジーコード、テザー
CharacterJoint角度を制限したボールソケット接続ラグドール(腰、肩)
ConfigurableJoint完全にカスタマイズ可能な制約特殊な接続全般
ジョイントのプロパティ
  • 接続ボディ:もう一方の Rigidbody(null = ワールドに固定)
  • アンカー/接続アンカー:ローカル空間での取り付けポイント
  • 破断力/破断トルク:ジョイントを破棄するしきい値
  • Enable Preprocessing:ジョイントのシミュレーションを安定させます

精密な関節動作が必要な産業/ロボット工学の用途では、通常のジョイントではなく ArticulationBody を使用してください。


2D 物理演算の違い

Unity の 2D 物理演算では、2D ワークフローに最適化された独立したエンジンを使用します。

項目3D2D
エンジンPhysXBox2D
RigidbodyRigidbodyRigidbody2D
ColliderColliderCollider2D
物理演算クラスPhysicsPhysics2D
ベクトルVector3Vector2
回転Quaternion(3 軸)float(Z 軸のみ)
重力Vector3Vector2
ForceModeForceModeForceMode2D
Rigidbody2D のボディタイプ
タイプ説明
Dynamic完全にシミュレートされ、力と重力に反応します
Kinematicスクリプトで移動し、衝突を検出しますが、力の影響は受けません
Static動かないオブジェクトで、レベルのジオメトリに使用します
2D のコライダータイプ

BoxCollider2D、CircleCollider2D、CapsuleCollider2D、PolygonCollider2D、EdgeCollider2D、CompositeCollider2D、TilemapCollider2D

2D 固有の機能
  • Effectors 2D:力の相互作用に使う Area、Buoyancy、Platform、Point、Surface エフェクター
  • Constant Force 2D:持続的な力/トルクを適用します
  • Physics Material 2D:摩擦と反発のプロパティ
  • LowLevelPhysics2D API:独立した低レベルの物理演算経路

2D API の詳細については、リファレンスファイル references/physics2d-api.md を参照してください。


よく使われるパターン

Rigidbody を使ったプレイヤーの移動
public class PlayerMovement : MonoBehaviour
{
    public float moveSpeed = 5f;
    public float jumpForce = 7f;

    private Rigidbody rb;
    private bool jumpRequested;

    void Awake()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        // Capture input in Update (legacy Input Manager; see unity-input for new Input System)
        if (Input.GetButtonDown("Jump"))
            jumpRequested = true;
    }

    void FixedUpdate()
    {
        // Apply physics in FixedUpdate (legacy Input; see unity-input)
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 move = new Vector3(h, 0f, v) * moveSpeed;
        rb.linearVelocity = new Vector3(move.x, rb.linearVelocity.y, move.z);

        if (jumpRequested)
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
            jumpRequested = false;
        }
    }
}
SphereCast を使った接地判定
// Cache collider reference in Awake() -- avoid GetComponent in hot paths
private CapsuleCollider capsule;
void Awake() => capsule = GetComponent<CapsuleCollider>();

public bool IsGrounded()
{
    float radius = 0.3f;
    return Physics.SphereCast(transform.position, radius, Vector3.down,
        out _, (capsule.height / 2f) - radius + 0.1f,
        LayerMask.GetMask("Ground"));
}
トリガーを使ったホバーパッド
public class HoverPad : MonoBehaviour
{
    public float hoverForce = 12f;

    void OnTriggerStay(Collider other)
    {
        if (other.attachedRigidbody != null)
            other.attachedRigidbody.AddForce(Vector3.up * hoverForce, ForceMode.Acceleration);
    }
}
非アロケーションの Raycast(GC ゼロ)
private readonly RaycastHit[] hits = new RaycastHit[10];

void DetectEnemies()
{
    int count = Physics.RaycastNonAlloc(transform.position, transform.forward,
        hits, 50f, LayerMask.GetMask("Enemies"));
    for (int i = 0; i < count; i++)
        Debug.Log("Hit: " + hits[i].collider.name);
}

アンチパターン

物理演算の力に Update を使用しないでください
// BAD: Forces applied at variable frame rate cause inconsistent behavior
void Update()
{
    rb.AddForce(Vector3.forward * 10f); // WRONG
}

// GOOD: Use FixedUpdate for physics
void FixedUpdate()
{
    rb.AddForce(Vector3.forward * 10f); // CORRECT
}
Transform で Rigidbody を移動しないでください
// BAD: Bypasses physics, breaks collision detection
transform.position += Vector3.forward * speed * Time.deltaTime; // WRONG

// GOOD: Use Rigidbody methods
rb.MovePosition(rb.position + Vector3.forward * speed * Time.fixedDeltaTime); // CORRECT
// Or apply forces:
rb.AddForce(Vector3.forward * speed);
プリミティブで十分な場合に MeshCollider を使用しないでください

単純な箱形オブジェクトに MeshCollider を使うのは非効率です。代わりに BoxCollider を使ってください。単純な形状では、はるかに軽量で同等の精度が得られます。MeshCollider は複雑な凹形状に限って使用してください。

物理演算のコールバック内でメモリを確保しないでください
// BAD: GC allocation every collision
void OnCollisionEnter(Collision other) {
    var enemies = GameObject.FindGameObjectsWithTag("Enemy"); // WRONG
}
// GOOD: Cache in Start(), reuse in callbacks
Raycast でレイヤーマスクを無視しないでください
Physics.Raycast(origin, direction, out hit);                        // BAD: hits everything
Physics.Raycast(origin, direction, out hit, 100f,
    LayerMask.GetMask("Ground", "Obstacles"));                      // GOOD: filtered

主要 API クイックリファレンス

カテゴリ主なメンバー
Physics(静的)Raycast、RaycastAll、RaycastNonAlloc、SphereCast、BoxCast、CapsuleCast、Linecast、OverlapSphere、OverlapBox、CheckSphere、CheckBox、ClosestPoint、ComputePenetration、Simulate、SyncTransforms
Physics プロパティgravity、defaultContactOffset、bounceThreshold、sleepThreshold、defaultSolverIterations、queriesHitTriggers、queriesHitBackfaces、simulationMode
Rigidbodymass、linearDamping、angularDamping、useGravity、isKinematic、linearVelocity、angularVelocity、interpolation、collisionDetectionMode、AddForce()、AddTorque()、MovePosition()、MoveRotation()、Sleep()、WakeUp()
コールバックOnCollisionEnter(Collision)、OnCollisionStay、OnCollisionExit、OnTriggerEnter(Collider)、OnTriggerStay、OnTriggerExit

メソッドシグネチャ、パラメーター、オーバーロードの詳細については、references/physics3d-api.md を参照してください。 2D 物理演算 API の全容については、references/physics2d-api.md を参照してください。


CharacterController

物理演算に依存しないキャラクターの移動(FPS コントローラー、NPC など)には、Rigidbody の代わりに CharacterController を使用してください。物理演算のシミュレーションを行わずに、斜面や段差、衝突時の滑りを処理します。API、パターン、CharacterController と Rigidbody の比較については、references/character-controller.md を参照してください。

関連スキル

  • unity-foundations -- GameObject の階層、コンポーネント、トランスフォーム、レイヤー
  • unity-scripting -- MonoBehaviour のライフサイクル(Update と FixedUpdate)、コルーチン
  • unity-2d -- 2D ゲーム開発のパターン、スプライトのレンダリング

Additional Resources

コメント