タイトル: 衝突時の処理
SEOタイトル: Unity 衝突検知 (Collision) 完全ガイド(Collider / Rigidbody / Trigger / Layer Matrix)
| この記事の要点 |
|
衝突検知が動く条件
Unity で「物にぶつかった」イベントを取るには、最低限3 つの条件が必要です:
- 双方の GameObject に Collider が付いている(Box / Sphere / Capsule / Mesh など)
- 少なくとも片方に Rigidbody が付いている(Kinematic でも可)
- Layer Collision Matrix で衝突が許可されている
Rigidbody が無い静止物どうしは Static Collider 扱いで、物理エンジンが移動しないと見なすため、衝突イベントを発生させません。
Collider の種類
| Collider | 形状 | コスト | 用途 |
|---|---|---|---|
| Box Collider | 箱 | 低 | 建物、家具、ブロック |
| Sphere Collider | 球 | 低 | ボール、爆発範囲 |
| Capsule Collider | カプセル | 低 | 人型キャラ |
| Mesh Collider | メッシュ形状そのまま | 高 | 不規則な地形(Convex=ON で動的にも使える) |
| Terrain Collider | 地形専用 | 中 | Terrain と組 |
| Wheel Collider | 車輪専用 | 中 | 車両物理 |
OnCollisionEnter / Stay / Exit
物理的にぶつかったときに呼ばれるコールバック。引数の Collision から接触点や相手オブジェクトを取得できます:
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class BulletCollision : MonoBehaviour
{
public int damage = 10;
void OnCollisionEnter(Collision col)
{
// 相手の GameObject
GameObject other = col.gameObject;
// Tag で判定(推奨: 文字列比較より高速)
if (other.CompareTag("Enemy"))
{
other.GetComponent()?.TakeDamage(damage);
Destroy(gameObject); // 弾を消す
}
// 接触点情報
ContactPoint contact = col.contacts[0];
Vector3 hitPos = contact.point;
Vector3 hitNormal = contact.normal;
// 相対速度(強い衝撃の判定など)
float impact = col.relativeVelocity.magnitude;
if (impact > 10f)
{
// 大ダメージ
}
}
void OnCollisionStay(Collision col)
{
// 接触し続けている間、毎 FixedUpdate に呼ばれる
}
void OnCollisionExit(Collision col)
{
// 離れた瞬間
}
}
OnTriggerEnter / Stay / Exit(すり抜けトリガー)
Collider の Is Trigger にチェックを入れると物理的な反発はせず、すり抜けながらイベントだけ発火します。「エリアに入ったら〜」「アイテム取得」などに最適:
using UnityEngine;
// アイテム取得トリガーの例
public class ItemPickup : MonoBehaviour
{
public int value = 10;
void OnTriggerEnter(Collider other)
{
// 引数は Collision ではなく Collider なので注意
if (other.CompareTag("Player"))
{
PlayerInventory inv = other.GetComponent();
inv?.AddItem(value);
Destroy(gameObject);
}
}
void OnTriggerStay(Collider other)
{
// エリア内に居続ける間(毒沼ダメージ等)
}
void OnTriggerExit(Collider other)
{
// 離脱
}
}
Collision と Trigger の使い分け
| OnCollision* | OnTrigger* | |
|---|---|---|
| Is Trigger | OFF | ON(どちらか一方で良い) |
| 物理反発 | あり | なし(すり抜け) |
| 引数の型 | Collision | Collider |
| 接触点情報 | 取れる | 取れない |
| 用途 | 弾と敵、ボールと壁 | アイテム、エリア、当たり判定 |
2D の場合
2D ゲームでは 2D 専用 API を使います。形式は同じです:
- Collider2D(BoxCollider2D / CircleCollider2D / PolygonCollider2D 等)
- Rigidbody2D
OnCollisionEnter2D(Collision2D col)/OnTriggerEnter2D(Collider2D other)
Layer Collision Matrix
レイヤー単位で「このレイヤーと、このレイヤーは衝突する/しない」を制御できます:
- Edit > Project Settings > Physics
- 下部の Layer Collision Matrix でチェックボックス操作
- 例: 「Enemy」と「EnemyBullet」を OFF にすると、敵が自分の弾に当たらない
CompareTag によるフィルタ
相手の判定はCompareTag を使うのが定石です。== "Tag" よりも高速で、未定義 Tag を渡すと警告も出ます:
// ❌ 遅い(文字列生成 + 比較)
if (other.tag == "Enemy") { ... }
// ✅ 推奨
if (other.CompareTag("Enemy")) { ... }
// 複数 Tag を比較するなら
string t = other.tag;
switch (t)
{
case "Enemy": ... break;
case "Boss": ... break;
}
Physic Material(摩擦と反発)
Collider に Physic Material をアタッチすると、物理的な質感を変えられます:
| 項目 | 値の例 | 効果 |
|---|---|---|
| Dynamic Friction | 0.0 (氷) - 1.0 (ゴム) | 動いてる物の摩擦 |
| Static Friction | 0.0 - 1.0 | 止まってる物の摩擦 |
| Bounciness | 0.0 (落ちて止まる) - 1.0 (永遠に跳ねる) | 反発係数 |
| Friction Combine | Average / Minimum / Multiply / Maximum | 2 物体の摩擦合成法 |
| Bounce Combine | 同上 | 反発合成法 |
高速移動オブジェクトのすり抜け対策(CCD)
弾丸など高速で動くオブジェクトは、1 フレームに薄い壁を飛び越えて衝突を見落とすことがあります。Rigidbody の Collision Detection を変更:
| モード | コスト | 用途 |
|---|---|---|
| Discrete(既定) | 低 | 通常物体 |
| Continuous | 中 | 高速移動物 → 静止物への当たり |
| Continuous Dynamic | 高 | 高速移動物 → 高速移動物 |
| Continuous Speculative | 中 | 新方式、回転にも強い |
イベントが来ない時のチェックリスト
- 双方に Collider があるか
- 少なくとも片方に Rigidbody があるか(IsKinematic でも可)
- Mesh Collider どうしの場合、片方は Convex か
- Layer Collision Matrix で OFF にしていないか
- Is Trigger と Collision 用イベントを混同していないか
- 関数名のスペルが正しいか(
OnTriggerEnter≠OnTriggerEntered) - Time Scale が 0 でないか
- Active / Enabled がオフでないか
FAQ
Q: Rigidbody を付けたくない
A: Is Kinematic = true の Rigidbody を付ければ物理影響を受けずに衝突イベントだけ取れます。
Q: OnCollisionEnter は呼ばれるが OnCollisionStay が呼ばれない
A: 接触中の Rigidbody が Sleep 状態になると Stay が止まります。Rigidbody.sleepThreshold を下げるか、毎フレーム小さな力を加えてください。
Q: トリガーを Raycast で取りたい
A: Physics.queriesHitTriggers を ON にするか、Physics.Raycast(..., QueryTriggerInteraction.Collide) を指定。