Collision Events
Collision Events は OnCollisionEnter・Stay・Exit の三つのコールバックで、接触点・衝撃力・相対速度・相手 Collider を報告します。ヒット音や破片演出、破壊判定の実装パターンを実践的に学べます。図解とシミュレーターで接触データを追い、自学にも使えます。
想像してみてください...
Collision Events は事故の保険レポートのようなものです。二台がぶつかると (OnCollisionEnter)、誰が誰に、どれくらいの速さで、どこで当たったかが記録されます。 接触中(OnCollisionStay)は記録が続き、離れると(OnCollisionExit)ファイルが閉じます。 `Collision` オブジェクトがそのレポート——衝撃力、ワールド接触点、相手です。
概念の詳細
Unity Physics で二つの Collider が衝突すると(Trigger ではない場合)、エンジンは三つのコールバックを発火します:
最初のフレームで OnCollisionEnter(Collision)、
続く物理フレームごとに OnCollisionStay(Collision)、
離れたときに OnCollisionExit(Collision)。Collision 引数が
接触データの全体を持ちます。
Collision が公開するもの:collision.gameObject(相手)、
collision.contacts(位置と法線付きの接触点)、
collision.relativeVelocity(相対速度——衝撃の強さとしてよく使う)、
collision.impulse(総インパルス)。
これらのコールバックはソルバー後の物理ステップで走ります。
ここで大量生成やアセット読み込みをしないでください——フラグを立てるかイベントをキューし、重い処理は Update へ。
OnCollisionStay は多くの剛体が互いに寄りかかると特に重い——
Physics.reuseCollisionCallbacks = true を検討してください。
両方に Collider が必要で、少なくとも一方に非 kinematic の Rigidbody が必要です。静的 Collider は Dynamic Rigidbody に当たればコールバックを受け取れますが、 静的同士は衝突を報告しません。
Collision オブジェクト内のデータ
Collision collision
ハンズオン手順
MonoBehaviour にコールバックを追加
OnCollisionEnter(Collision collision) — Unity が呼ぶのでイベント登録は不要です。
collision.relativeVelocity.magnitude を読む
衝撃の強さとして使う:軽い → 静かなタップ、重い → ダメージ、粉砕…
最初の接触点を取る
collision.GetContact(0) または collision.contacts[0].point — 正確なヒット位置にパーティクルやデカールを生成。
Tag や Layer でフィルタ
ロジックの前に collision.gameObject.CompareTag("Enemy") — 無関係なヒットを無視。
OnCollisionStay を使いすぎない
「触れているか」だけなら Enter/Exit で bool を立て、Stay ではなく Update で読む。
インタラクティブシミュレーター
"Fire" をクリックして弾を壁へ——衝突イベントが順にログされる様子を確認。
「発射」を押して collision events を確認...
コード例
基本接触点で音を再生し、パーティクルを生成する。
using UnityEngine;
public class CollisionSounds : MonoBehaviour
{
public AudioClip softHit, hardHit;
public ParticleSystem impactFX;
public float hardHitThreshold = 5f;
void OnCollisionEnter(Collision collision)
{
float speed = collision.relativeVelocity.magnitude;
// Pick a clip from impact speed
AudioClip clip = speed > hardHitThreshold ? hardHit : softHit;
AudioSource.PlayClipAtPoint(clip, collision.GetContact(0).point);
// Spawn FX at the first contact
if (impactFX != null)
{
ContactPoint contact = collision.GetContact(0);
Instantiate(impactFX, contact.point,
Quaternion.LookRotation(contact.normal));
}
}
}コード例
上級衝撃が十分強いと粉砕——破片を生成して元を破棄。
using UnityEngine;
public class BreakableObject : MonoBehaviour
{
public GameObject[] fragmentPrefabs; // Debris pieces
public float breakForceThreshold = 8f;
public float fragmentExplosionForce = 200f;
bool broken = false;
void OnCollisionEnter(Collision collision)
{
if (broken) return;
if (collision.relativeVelocity.magnitude < breakForceThreshold) return;
broken = true;
ContactPoint contact = collision.GetContact(0);
// Spawn and scatter fragments
foreach (GameObject frag in fragmentPrefabs)
{
GameObject piece = Instantiate(frag, transform.position,
Random.rotation);
Rigidbody rb = piece.GetComponent<Rigidbody>();
if (rb != null)
rb.AddExplosionForce(fragmentExplosionForce,
contact.point, 1f);
}
Destroy(gameObject);
}
}📌 要点
- ▸Enter → Stay → Exit、常にこの順
- ▸relativeVelocity.magnitude = 衝撃の強さ
- ▸contacts[0].point = ワールド空間のヒット位置
- ▸contacts[0].normal = ヒット時の面の向き
- ▸静的同士は OnCollisionEnter を呼ばない
⚠️ よくあるミス
❌ OnCollisionStay 毎フレームで物理をいじる
不安定なジッターとヒッチ
✅ Enter/Exit でフラグを立て、ロジックは FixedUpdate
❌ 長さチェックなしで contacts[] をインデックス
contacts が空 → IndexOutOfRange
✅ GetContact(0) を使うか contacts.Length > 0 を確認