Unityで衝突(Collision)とトリガー(Trigger)をUnityEventで管理するチュートリアル

本資料では、Unityの物理演算における衝突(Collision) および トリガー(Trigger) イベントを、UnityEvent を利用して柔軟にハンドリングする方法を解説します。直接 OnCollisionEnter / OnTriggerEnter を実装するだけでなく、インスペクター上でイベントに紐づけるメソッドを自由に差し替えられる点に注目してください。


1. チュートリアルの概要

1.1 目的

  • 柔軟なイベント管理: 衝突・トリガーイベントを UnityEvent として公開することで、インスペクター上で簡単に複数のイベントハンドラを登録・変更できます。
  • 実践的な応用: 基本的な物理イベント処理に加え、トラブルシューティングのポイントやエラーハンドリングの注意点を学びます。

1.2 必要なスキルレベル

  • Unityエディタの基本操作: GameObjectの作成、コンポーネントの追加・設定、シーンの保存と実行など。
  • C#の基本文法: MonoBehaviour の継承、メソッド定義、デバッグログ出力(Debug.Log)など。
  • 物理コンポーネントの基礎知識: Collider、Rigidbody、Is Triggerの使い分けなど。

2. 使用するスクリプト

2.1 CollisionTriggerHandler.cs

物理衝突発生時に UnityEvent を通じて処理を呼び出すスクリプトです。

using UnityEngine;
using UnityEngine.Events;

public class CollisionTriggerHandler : MonoBehaviour
{
    // インスペクター上でハンドラ登録可能な UnityEvent
    public UnityEvent<Collision> OnCollisionEnterEvent;

    private void OnCollisionEnter(Collision collision)
    {
        // 衝突時にイベントが正しく呼び出されているか、デバッグログで確認
        Debug.Log("衝突検知: " + collision.gameObject.name);
        OnCollisionEnterEvent?.Invoke(collision);
    }
}

public UnityEvent<Collision> OnCollisionEnterEvent; は、以下の点で重要な役割を果たします。

  • パブリックフィールドとして宣言
    この変数は public として宣言されているため、Unityエディタのインスペクターに表示され、エディタ上で設定やイベントリスナーの登録が可能です。
  • ジェネリックなUnityEvent
    UnityEvent<Collision> は、ジェネリック型のUnityEventで、引数として Collision 型の情報を受け取ります。
    これにより、衝突が発生した際に、衝突情報(Collision オブジェクト)を引数として渡すことができるイベントリスナーを登録できます。
  • イベントハンドリングの柔軟性
    このフィールドにより、スクリプト内で直接処理を記述するのではなく、Unityエディタ上で簡単に複数のメソッド(イベントリスナー)を登録でき、衝突時の処理を柔軟に変更できます。
    登録されたリスナーは、衝突時に Collision 情報を受け取り、各自の処理を実行します。

まとめると、public UnityEvent<Collision> OnCollisionEnterEvent; は、衝突イベントが発生した際に、衝突の詳細情報を引数として渡すイベントを定義し、インスペクターからイベントリスナーを設定できるようにするための宣言です。

private void OnCollisionEnter(Collision collision) は、Unity の物理エンジンによって自動的に呼び出されるコールバックメソッドで、以下のような意味と役割を持ちます。

  • 自動呼び出し:
    このメソッドは、オブジェクト同士が衝突した際に Unity が自動的に実行します。つまり、プログラマーが明示的に呼び出す必要はありません。
  • 引数 Collision collision:
    衝突時の詳細情報(接触点、衝突相手の GameObject や Rigidbody など)を持つ Collision オブジェクトが渡されます。この情報を利用して、どのような衝突が起きたかを判断できます。
  • メソッドのアクセス修飾子 private:
    メソッドは private として宣言されているため、クラス外からは呼び出せず、Unity の内部処理でのみ自動的に呼び出されます。
  • イベントのトリガー:
    このメソッド内で、衝突時の情報を他の処理へ伝達するために OnCollisionEnterEvent?.Invoke(collision); を呼び出している場合、登録されたイベントリスナーに衝突情報が渡され、後続の処理が実行されます。

まとめると、private void OnCollisionEnter(Collision collision) は、Unity の物理システムが衝突を検出した際に自動で実行されるメソッドで、衝突の詳細な情報を受け取り、必要に応じてイベントやその他の処理を呼び出すためのエントリーポイントとなります。

OnCollisionEnterEvent?.Invoke(collision); は、以下のような役割と意味を持つコードです。

  • UnityEventの呼び出し:
    OnCollisionEnterEventUnityEvent<Collision> 型のイベントです。これは、衝突が発生した際に、インスペクターやコード上で登録された複数のリスナー(イベントハンドラ)を呼び出すためのものです。
  • Null条件演算子(?.):
    ?. は、null条件演算子と呼ばれ、対象が null でなければその後ろのメソッドを実行し、もし null なら何も実行せずにスキップするという意味です。
    この場合、OnCollisionEnterEventnull でなければ Invoke(collision) を呼び出し、null の場合は何も起こりません。これにより、イベントが登録されていないときに NullReferenceException が発生するのを防ぎます。
  • Invokeメソッド:
    Invoke(collision) は、登録されているすべてのイベントリスナーを、引数 collision を渡して呼び出すためのメソッドです。つまり、衝突時の詳細情報が各リスナーに伝えられ、各々のハンドラーで適切な処理を実行できるようになります。

まとめると、このコードは「もし OnCollisionEnterEvent に何らかのリスナーが登録されていれば、発生した衝突情報(collision)をそのリスナーたちに通知(呼び出し)する」という処理を行っています。

2.2 TriggerHandler.cs

トリガー領域に入った際に UnityEvent を呼び出すスクリプトです。

using UnityEngine;
using UnityEngine.Events;

public class TriggerHandler : MonoBehaviour
{
    public UnityEvent<Collider> OnTriggerEnterEvent;

    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("トリガー検知: " + other.gameObject.name);
        OnTriggerEnterEvent?.Invoke(other);
    }
}

以下、それぞれの型が持つ意味と役割を説明します。


Collision 型

  • 物理衝突の詳細情報を提供
    Collision 型は、通常の衝突(つまり、物理エンジンによる力の作用が発生する場合)の際に渡されるデータです。
  • 接触点情報: 衝突した際の接触点や衝突面の法線など、衝突の詳細な情報を含みます。
  • 衝突力・速度: 衝突時の相対速度や衝突力(衝撃量)の情報が得られ、物理的な反応(例えば、跳ね返りなど)の処理に利用できます。
  • 衝突オブジェクトの情報: 衝突した相手のGameObject、Rigidbody、Colliderなども参照可能です。

Collider 型

  • トリガーイベントの発生時に利用
    Collider 型は、主にトリガーイベントで使用される型です。トリガーは物理的な衝突反応を発生させず、エリアに入ったことなどを検知する用途に用います。
  • シンプルな情報提供: トリガーに侵入した相手のColliderコンポーネントの情報が渡されるため、どのオブジェクトがエリアに侵入したかを簡単に把握できます。
  • 物理反応なし: 衝突とは異なり、トリガーでは物理シミュレーションによる反発などは発生せず、単に侵入・退出の検知が目的です。

まとめ

  • Collision:
    衝突イベント時に、衝突の詳細な物理情報(接触点、衝突力、相手のRigidbody情報など)を取得するための型です。物理シミュレーションが関与する場合に使用します。
  • Collider:
    トリガーイベント時に、どのColliderがエリアに入ったかなどのシンプルな情報を取得するための型です。物理的な反発や衝突力は関与しません。

これらの違いを理解することで、必要な情報に応じた適切なイベントハンドリングが実装できるようになります。

2.3 Example.cs

実際の処理(ログ出力)を実装したサンプルスクリプトです。
インスペクター上でこれらのメソッドをイベントに紐付けて利用します。

using UnityEngine;

public class Example : MonoBehaviour
{
    public void HandleCollisionEnter(Collision collision)
    {
        Debug.Log("衝突発生: " + collision.gameObject.name);
    }

    public void HandleTriggerEnter(Collider other)
    {
        Debug.Log("トリガー発生: " + other.gameObject.name);
    }
}


3. シーンのセットアップ

3.1 プロジェクトの準備

  1. Unityで新規または既存のプロジェクトを開きます。
  2. 上記3つのスクリプトファイル(CollisionTriggerHandler.csTriggerHandler.csExample.cs)をプロジェクト内の任意のフォルダ(例:Scripts)に配置します。

3.2 ゲームオブジェクトの配置と設定

  1. 物理衝突を扱うオブジェクト(例:Cube)
    • シーンに3Dオブジェクト(Cube)を配置。
    • Collider(Box Collider)が自動追加されるので確認します。
    • Rigidbody を追加。Rigidbodyがないと物理衝突が発生しないため注意!
    • オブジェクトに CollisionTriggerHandler をアタッチ。
  2. トリガーを扱うオブジェクト(例:Sphere)
    • シーンに3Dオブジェクト(Sphere)を配置。
    • Collider(Sphere Collider)を確認し、Is Trigger オプションをオンにする。
    • 必要に応じて Rigidbody を追加(移動や物理判定が必要な場合)。
    • オブジェクトに TriggerHandler をアタッチ。
  3. イベント受信オブジェクト(例:EventReceiver)
    • 空のゲームオブジェクトを作成し、Example スクリプトをアタッチします。
    • 名前を「EventReceiver」など、役割が分かるように設定。

3.3 シーン図

複数の情報を表示するために、あえて、複数のウィンドウを表示しています


4. UnityEventのイベント紐付け

4.1 CollisionTriggerHandler の設定

  1. シーン内の衝突オブジェクト(CollisionTriggerHandler を持つオブジェクト)を選択します。
  2. インスペクターに表示される OnCollisionEnterEvent フィールドを確認。
  3. 「+」ボタンをクリックして新しいイベント要素を追加。
  4. オブジェクトの参照に、Example スクリプトがアタッチされた「EventReceiver」をドラッグ&ドロップ。
  5. ドロップダウンから Example.HandleCollisionEnter(Collision) を選択。

4.2 TriggerHandler の設定

  1. シーン内のトリガーオブジェクト(TriggerHandler を持つオブジェクト)を選択します。
  2. インスペクターの OnTriggerEnterEvent フィールドを確認。
  3. 「+」ボタンをクリックして新しいイベント要素を追加。
  4. オブジェクトの参照に、「EventReceiver」を設定。
  5. ドロップダウンから Example.HandleTriggerEnter(Collider) を選択。

5. 実行と確認

  1. シーンを保存し、Play モードにします。
  2. 以下の動作を試して、イベントが正しく発火するか確認してください。
    • 衝突テスト: Rigidbodyを持つCubeを落下させ、別のオブジェクトに衝突させる。
    • トリガーテスト: Is Trigger が有効なオブジェクトに、他のColliderが侵入するように移動させる。
  3. Console タブでログを確認し、以下のような出力があれば成功です。
    • 衝突時: 衝突発生: [衝突したオブジェクト名]
    • トリガー時: トリガー発生: [侵入したオブジェクト名]

6. トラブルシューティングとエラーハンドリング

  • Rigidbodyの設定確認:
    衝突が発生しない場合、対象オブジェクトにRigidbodyが正しく追加されているか確認しましょう。Rigidbodyがなければ物理演算が働かず、イベントが呼ばれません。
  • Colliderの設定:
    Is Trigger が正しく設定されているか。
    ・衝突オブジェクトには通常のCollider、トリガーオブジェクトにはIs TriggerがオンのColliderが必要です。
  • NullReferenceException の回避:
    ・UnityEventにイベントリスナーが正しく登録されていないと、意図した動作にならない場合があります。インスペクターでイベントリストが空になっていないか確認してください。
    ・デバッグログを活用して、イベントが発火しているかどうかをチェックしましょう。

7. 応用例と拡張

  • 複数イベントの連携:
    UnityEventは複数のメソッドを同時に登録できるため、同一イベントで複数の処理を連携させることが可能です。たとえば、衝突時にスコア加算やエフェクト再生など、複数のアクションを実行できます。
  • 2D環境での実装:
    2Dゲームの場合は、OnCollisionEnter2D / OnTriggerEnter2DUnityEvent<Collision2D> / UnityEvent<Collider2D> を用いることで、同様の仕組みを実装できます。コード例は上記のスクリプトをベースに調整してください。
  • エディタ拡張:
    イベントの紐付けやデバッグ情報をより分かりやすくするために、エディタ拡張でカスタムインスペクターを作成する方法もあります。

8. まとめ

  • 柔軟なイベント管理:
    CollisionTriggerHandlerTriggerHandler により、物理衝突やトリガーイベントをUnityEventとして公開することで、インスペクターから簡単にイベントハンドラを追加・変更できます。
  • 基礎から応用まで:
    本チュートリアルでは、基本的なスクリプトの記述から、シーン上での設定方法、トラブルシューティング、さらには2D対応やエディタ拡張の応用例までを解説しました。
  • 実践的な確認:
    デバッグログやUnityEventの正しい登録、ColliderとRigidbodyの設定など、実際の動作確認とエラー対応のポイントも確認することで、より実践的な開発力が身に付きます。

このチュートリアルを通じて、Unityでの物理イベント管理の基本から応用までの流れをしっかりと理解し、実際のプロジェクトに役立ててください。

Unity,イベント

Posted by hidepon