衝突とトリガー:なぜイベントが発火しないのか
OnCollisionEnter / OnTriggerEnter が呼ばれないのはなぜ?
両方のオブジェクトに collider が必要で、片方には Rigidbody も必要です。OnCollisionEnter なら kinematic 以外、OnTriggerEnter なら kinematic でも可。続けてメソッド名と引数、スクリプトが collider を持つオブジェクトに付いているか、二つの層が Layer Collision Matrix で今も相互に有効かを確かめてください。
画面の中で二つのオブジェクトが触れ合っているのに、あなたのメソッドは実行されない。Console には何も出ず、エラーも警告もなし——Unity は単に一度も呼び出さなかっただけです。原因はたったの六つで、全部確かめるのに一分もかかりません。
まず最初:二つのイベントのうち、どちらが必要か
✓ OnCollisionEnter
solid hits solid
Collision で、接触点と衝突時の速度が入っています。✓ OnTriggerEnter
something enters an area
Collider:何が入ってきたかだけで、衝突の情報はありません。六つのチェック、この順番で
- 1
どちらかの側に Rigidbody。物理が二つのうち一方を監視しているときだけ、Unity は接触を報告します。衝突イベントには少なくとも片側に kinematic でない Rigidbody が必要。トリガーイベントなら片側に Rigidbody があればよく、kinematic でも構いません。二つとも静かに置かれているだけなら、何も報告されません。
- 2
メソッド名と引数。
OnTriggerEnter(Collider other)とOnCollisionEnter(Collision collision)——一字一句このとおりに書いたものだけが有効です。Unity は名前でメソッドを探すため、onTriggerEnterや、3D シーンでのCollider2Dはコンパイルは通っても決して呼ばれません。 - 3
スクリプトが正しいオブジェクトに付いているか。メッセージは、コライダーを持つ GameObject と、そのコライダーが属する Rigidbody を持つ GameObject の両方に送られます。その二つより親側のスクリプトには何も届きません。
- 4
両方のコライダーが存在し、有効であるか。Inspector を見るのが最速です:Play を押してそのモノに歩いて近づけ、Scene ウィンドウで二つのコライダーのアウトラインが本当に重なっているか確かめます。既定サイズのままのコライダーは、モデルにすっぽり収まっていることがよくあります。
- 5
二つのレイヤーは出会いを許可されているか。 に Layer Collision Matrix があります。そこでチェックが外れているマスが一つでもあると、二つのオブジェクトは完全に互いを無視します——衝突もトリガーもメッセージもなし。
- 6
2D と 3D は決して交わらない。
Collider2DとColliderは同じシーンを共有する別々の物理エンジンです。2D コライダーが 3D コライダーに触れることはなく、2D のイベントは必ず末尾が2Dの方です。
ちゃんと動くトリガーと、ちゃんと動く衝突の両方
using UnityEngine;
// The coin sits still, so the Rigidbody lives on the player instead.
[RequireComponent(typeof(Collider))]
public class Coin : MonoBehaviour
{
public int value = 1;
void Reset()
{
// Runs when the component is added: tick Is Trigger for whoever forgets.
GetComponent<Collider>().isTrigger = true;
}
void OnTriggerEnter(Collider other)
{
// Anything can walk in here — check who it was before scoring.
if (!other.CompareTag("Player")) return;
// Wire this into whatever keeps your score.
Debug.Log($"+{value}");
Destroy(gameObject);
}
}using UnityEngine;
[RequireComponent(typeof(Rigidbody), typeof(Collider))]
public class Crate : MonoBehaviour
{
public AudioSource thud;
void OnCollisionEnter(Collision collision)
{
// Collision carries the impact: a light nudge should not sound like a crash.
if (collision.relativeVelocity.magnitude < 2f) return;
thud.Play();
}
}見落としがちな、まだ二つある
CharacterController は Rigidbody ではありません。OnCollisionEnter は決して呼ばれず、代わりに OnControllerColliderHit が呼ばれます——ただし移動中にトリガーを起動するのは普通にするので、箱を押せないキャラでもコインは拾える、という現象が起きます。
十分な速さのあるオブジェクトは、二つのフレームの間に薄い壁をまっすぐ突き抜けてワープします。その Rigidbody の Collision Detection を Continuous に設定し、ついでに壁にも少し厚みを持たせましょう。
transform.position を直接書き換えて Rigidbody を動かすのはテレポートで、物理が判定できる経路が存在しません。Rigidbody.MovePosition か速度で動かせば、接触の報告は戻ってきます。
これを作るレッスン
弾、ダメージ、エフェクト
この記事はそれだけで完結するレシピです。コースでは同じものを、5 つのタブを貫くひとつのプロジェクトの一部として作ります — キャラクターと戦闘 のレッスン 05。