Unityにおける2Dゲーム開発において、オブジェクト同士の当たり判定(衝突判定)は非常に重要な要素です。
しかし、実装を進める中で「コードは正しいはずなのに OnCollisionEnter2D メソッドが呼ばれない(発火しない)」というトラブルは、多くの開発者が直面する典型的なつまずきポイントです。
本記事では、CircleCollider2D の radius 設定ミスといった初歩的な見落としから、Unityの物理演算システム(Physics 2D)の仕様に基づいた前提条件まで、OnCollisionEnter2D が機能しない際の原因と具体的な解決策を技術的な観点から解説します。
OnCollisionEnter2Dが発火するための前提条件
Unityの2D物理演算エンジンが「衝突」を検知し、スクリプト上の OnCollisionEnter2D を呼び出すためには、いくつかの厳密な前提条件が満たされている必要があります。まずは以下の基本構成がオブジェクトに適用されているかを確認してください。
- 衝突する双方のオブジェクトに、何らかの
Collider2D(BoxCollider2DやCircleCollider2Dなど)がアタッチされていること。 - 衝突する少なくとも一方のオブジェクトに、
Rigidbody2Dがアタッチされていること。 - 双方の
Collider2Dコンポーネントにおいて、**Is Triggerプロパティがfalse(チェックなし)**に設定されていること。
特に Rigidbody2D の設定は重要です。
双方のオブジェクトが Rigidbody2D を持たない場合、または両方の「Body Type」が Static(静的)に設定されている場合、Unityはそれらを動かない背景として扱い、衝突判定の計算を行いません。
よくある原因1:Collider2Dのサイズ(Radiusなど)が極端に小さい
OnCollisionEnter2D が呼ばれない原因として非常に多いのが、インスペクター上での「Colliderサイズの初期設定による未調整」です。
例えば、円形のオブジェクトに CircleCollider2D をアタッチした際、プロパティである Radius(半径)の数値が初期値のままになっており、実際のオブジェクト(Sprite)の見た目に対して当たり判定の範囲が極端に小さくなっているケースがあります。
【注意点】
見た目と物理判定の乖離 画面上ではオブジェクト同士が明確に重なって(ぶつかって)いるように見えても、内部の物理演算においては Collider の境界線同士が全く接触していないため、OnCollisionEnter2D はトリガーされません。
【解決策】
対象オブジェクトのインスペクターを開き、Collider2D コンポーネントの Edit Collider ボタンを押下して、シーンビュー上で当たり判定の緑色の枠線が Sprite の輪郭に沿うようにサイズ(RadiusやSize)を適切に拡大・調整してください。
よくある原因2:Is Triggerが有効になっている
当たり判定には、物理的な反発を伴う「Collision(衝突)」と、領域への侵入を検知する「Trigger(通過)」の2種類が存在します。
インスペクター上の Collider2D にある Is Trigger にチェックが入っている場合、物理的な衝突は発生せず、オブジェクト同士はすり抜けます。
この状態では OnCollisionEnter2D ではなく、OnTriggerEnter2D メソッドが呼ばれる仕様となっています。
物理的な壁や床、キャラクター同士のぶつかり合いを実装したい場合は、必ず Is Trigger を無効化(チェックを外す)してください。
よくある原因3:レイヤー衝突マトリックス(Layer Collision Matrix)の設定
コンポーネントの設定に問題がない場合、プロジェクト全体の物理演算設定によって特定のレイヤー間の衝突が意図的に無視されている可能性があります。
Unityには、特定のレイヤー同士の当たり判定を制御する「Layer Collision Matrix」という機能があります。
【確認手順】
1. メニューバーから Edit > Project Settings を開く。
2. 左側のタブから Physics 2D を選択する。
3. インスペクター下部にある Layer Collision Matrix を確認する。
ここで、衝突させたいオブジェクトに割り当てられているレイヤー同士の交差部分のチェックボックスが外れている場合、衝突判定は行われません。
必要な箇所にチェックが入っているかを確認してください。
よくある原因4:Rigidbody2Dのスリープ状態
Unityの物理演算エンジンは、パフォーマンス最適化のために、一定時間動きのない Rigidbody2D を「スリープ状態(Sleeping Mode)」に移行させます。
スリープ状態のオブジェクトに対して、Rigidbody2D を持たない(あるいはKinematicな)オブジェクトをスクリプトで直接座標移動(Transform.positionの変更など)させてぶつけた場合、物理演算エンジンが衝突を検知できず、OnCollisionEnter2D が呼ばれないことがあります。
【対策】Rigidbody2D コンポーネントの Sleeping Mode を Start Awake から Never Sleep に変更することでスリープを無効化できます。
ただし、パフォーマンスに影響を与える可能性があるため、基本的には Transform による直接移動ではなく、Rigidbody2D の velocity や AddForce を用いた物理的な移動処理を実装することが推奨されます。
OnCollisionトラブルシューティング・チェックリスト
OnCollisionEnter2D が呼ばれずに処理が止まってしまった場合は、以下の項目を順に確認することで、大半の問題を解決することが可能です。
・メソッド名のスペルや引数が間違っていないか(例:Collision ではなく Collision2D になっているか)
・双方に Collider2D がアタッチされ、適切なサイズ(Radius等)が設定されているか
・少なくとも一方に Rigidbody2D がアタッチされているか
・双方の Is Trigger のチェックが外れているか
・Project Settings の Layer Collision Matrix でレイヤー間の衝突が許可されているか
・Z軸(奥行き)の座標がずれていないか(2DであってもZ座標が異なると衝突しない場合があります)
当たり判定の実装は、スクリプトの正確性だけでなく、エディタ上のコンポーネント設定や物理演算エンジンの仕様理解が不可欠です。
本記事のチェックポイントを参考に、プロジェクトの設定を見直してみてください。
そのほかのUnity記事
-
uGUI
【Unity】Sceneビューで見えるのにGameビューで表示されない!原因と対処法まとめ
-
uGUI


【Unity】OnCollisionEnter2Dが呼ばれない!2D物理演算の衝突判定における原因と解決法
-
Android


UnityとAndroidネイティブの連携:UnitySendMessageの引数を使う
-
Rider


RiderでCannot Resolve Symbol
-
uGUI


【Unity】Image(Script)のSourceImageを変更する
-
Android


UnityとAndroidのデータ保存領域・パス取得方法まとめ
-
C#


【Unity】ParticleSystemで描画座標がズレてしまう時は
-
UNET


【Unity】IndexOutOfRangeException: NetworkReader:ReadBytes out of range
-
Asset


symlinkが含まれるUnitySDKを導入する時にGUIDが更新され続ける場合の対処
-
Unity


UnityでInvalid build path エラー
-
Android


【Unity/Android】エラー: パッケージ “com.unity3d.player” は存在しません
-
Animator


【Unity】Animatorの更新タイミングを変更する



