unity-physics について
Unity開発者向けの物理リファレンススキルです。3D・2D物理、Rigidbody、Collider、クエリ、ジョイント、一般的な実装パターンを解説します。
主な機能
- 013D・2D物理の概要
- 02Rigidbodyの設定と力の適用
- 03Collider、トリガー、コールバック
- 04レイキャスト、キャスト、重なり判定
- 05ジョイントの種類と用途
活用シーン
- 01Rigidbodyによる移動方法の選択
- 02トリガーイベントが発生しない原因の調査
- 03高速オブジェクトの衝突検出設定
- 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.mdphysics2d-api.mdphysics3d-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 |
isKinematic | true の場合、物理的な力による制御を受けません | 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 のプロパティ
| プロパティ | 型 | 説明 |
|---|---|---|
point | Vector3 | ワールド空間でのヒット位置 |
normal | Vector3 | ヒット位置における面の法線 |
distance | float | レイの始点からの距離 |
collider | Collider | ヒットした Collider |
transform | Transform | ヒットしたオブジェクトの 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 コンポーネントと空間内の固定点を接続します。
| ジョイントの種類 | 説明 | 使用例 |
|---|---|---|
| FixedJoint | 2 つのボディを固定します(ばねとして実装) | オブジェクトの取り付け、破断可能な接続 |
| HingeJoint | 単一軸を中心とした回転 | ドア、振り子、チェーン |
| SpringJoint | 距離を維持する弾性接続 | バンジーコード、テザー |
| CharacterJoint | 角度を制限したボールソケット接続 | ラグドール(腰、肩) |
| ConfigurableJoint | 完全にカスタマイズ可能な制約 | 特殊な接続全般 |
ジョイントのプロパティ
- 接続ボディ:もう一方の Rigidbody(null = ワールドに固定)
- アンカー/接続アンカー:ローカル空間での取り付けポイント
- 破断力/破断トルク:ジョイントを破棄するしきい値
- Enable Preprocessing:ジョイントのシミュレーションを安定させます
精密な関節動作が必要な産業/ロボット工学の用途では、通常のジョイントではなく ArticulationBody を使用してください。
2D 物理演算の違い
Unity の 2D 物理演算では、2D ワークフローに最適化された独立したエンジンを使用します。
| 項目 | 3D | 2D |
|---|---|---|
| エンジン | PhysX | Box2D |
| Rigidbody | Rigidbody | Rigidbody2D |
| Collider | Collider | Collider2D |
| 物理演算クラス | Physics | Physics2D |
| ベクトル | Vector3 | Vector2 |
| 回転 | Quaternion(3 軸) | float(Z 軸のみ) |
| 重力 | Vector3 | Vector2 |
| ForceMode | ForceMode | ForceMode2D |
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 |
| Rigidbody | mass、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 ゲーム開発のパターン、スプライトのレンダリング