【Unity】汎用的なイベントクラスのリファクタリング
接触中のオブジェクトを検出し、カスタムイベントを実行(つまり、指定するメソッドを実行)する方法について説明します
コードを変更することなく、自由に呼び出すメソッドが変更できること、また実行中にも臨機応変に呼び出すメソッドが変更できることが特徴です
基本のコード
using UnityEngine;
using System;
using UnityEngine.Events;
[RequireComponent(typeof(Collider))]
public class CollisionDetector : MonoBehaviour
{
[SerializeField] private TriggerEvent onTriggerStay = new TriggerEvent();
private void OnTriggerStay(Collider other)
{
onTriggerStay.Invoke(other);
}
}
[Serializable]
public class TriggerEvent : UnityEvent<Collider>
{
}
このコードはUnityで使うCollisionDetector
クラスを定義しています。[RequireComponent(typeof(Collider))]
属性により、このスクリプトがアタッチされたGameObjectにColliderコンポーネントが必須であることを保証します。TriggerEvent
はUnityEvent<Collider>
を継承したシリアライズ可能なカスタムイベントクラスで、Collider型のパラメータを持つイベントを定義しています。onTriggerStay
フィールドはエディタから設定可能で、OnTriggerStay
メソッドが他のオブジェクトとの接触を検出するとこのイベントが呼び出されます。これにより、特定の接触時のカスタムロジックを実装できます。
リファクタリングしたコード
using UnityEngine;
using UnityEngine.Events;
[RequireComponent(typeof(Collider))]
public class CollisionDetector : MonoBehaviour
{
// 明示的な初期化を省略してシリアライズフィールドを宣言
[SerializeField] private UnityEvent<Collider> onTriggerStay;
private void OnTriggerStay(Collider other)
{
onTriggerStay?.Invoke(other); // イベントがnullでない場合にのみInvokeを呼び出す
}
}
このコードでは、onTriggerStay
フィールドの初期化を省略しています。Unityのシリアライズシステムは、インスペクターからアクセス可能なUnityEvent
型のフィールドに自動的にインスタンスを割り当てます。このため、スクリプトがコンポーネントとしてGameObjectにアタッチされている限り、onTriggerStay
はnullにならず、安全に使用できます。
ただし、コード内でイベントを動的に扱う場合(例えば、スクリプトからイベントリスナーを追加するなど)は、null条件演算子(?.
)を使用してInvoke
を呼び出すことで、onTriggerStay
がnullでないことを保証すると良いでしょう。これは、スクリプトの実行中にonTriggerStay
が明示的にnullに設定される可能性があるためです。しかし、通常のUnityの使用法では、このようなケースは稀であり、インスペクターからの設定のみを行う場合には、nullチェックは必要ありません。
イベントハンドラ(実行したいメソッド)に渡す引数をカスタムできるようにしたコード
using UnityEngine;
using System;
// コライダーイベントのデータを保持するクラス。
[Serializable]
public class ColliderEventData
{
public Collider Collider { get; private set; }
public string Tag { get; private set; }
public int Layer { get; private set; }
public ColliderEventData(Collider collider)
{
Collider = collider;
Tag = collider.tag;
Layer = collider.gameObject.layer;
}
}
using UnityEngine;
using UnityEngine.Events;
[RequireComponent(typeof(Collider))]
public class CollisionDetector : MonoBehaviour
{
// ColliderEventDataを引数に取るUnityEventを直接使用
[SerializeField] private UnityEvent<ColliderEventData> onColliderStay = new UnityEvent<ColliderEventData>();
private void OnTriggerStay(Collider other)
{
var eventData = new ColliderEventData(other);
onColliderStay.Invoke(eventData);
}
}
使い方
シンプルな使用例を提供します。この例では、CollisionDetector
スクリプトを使って、UnityのCollider
コンポーネントが他のオブジェクトと接触している間にイベントを発生させ、そのイベントをリッスンして何らかのアクションを実行するシンプルなスクリプトを作成します。
ステップ 1: CollisionDetector
スクリプトの設定
まず、CollisionDetector
スクリプトを含むGameObjectにはCollider
コンポーネントが必要です(Is Trigger
オプションを有効にします)。そして、このスクリプトにはonColliderStay
イベントが公開されており、Unityエディタから直接イベントリスナーを設定できます。
ステップ 2: イベントリスナーを作成
次に、CollisionDetector
のonColliderStay
イベントをリッスンする簡単なリスナースクリプトを作成します。このスクリプトは、特定のコライダーとの接触を検出した時に実行されるアクションを定義します。
using UnityEngine;
// イベントリスナーとして機能するクラス
public class CollisionListener : MonoBehaviour
{
public void OnStayDetected(ColliderEventData eventData)
{
Debug.Log($"Stay Detected with object: {eventData.Collider.gameObject.name}, Tag: {eventData.Tag}, Layer: {eventData.Layer}");
}
}
ステップ 3: Unity エディタでイベントを設定
CollisionDetector
スクリプトをアタッチしたGameObjectに、Collider
コンポーネントがアタッチされていることを確認し、Is Trigger
を有効にします。CollisionListener
スクリプトをシーン内の任意のGameObjectにアタッチします。CollisionDetector
スクリプトのonColliderStay
イベントセクションに移動し、プラスアイコンをクリックして新しいイベントリスナーを追加します。CollisionListener
スクリプトをアタッチしたGameObjectをonColliderStay
の空のフィールドにドラッグ&ドロップします。- ドロップダウンメニューから
CollisionListener -> OnStayDetected(ColliderEventData)
関数を選択します。
これで、CollisionDetector
が他のオブジェクトと接触している間、CollisionListener
のOnStayDetected
メソッドが呼び出され、コンソールに接触しているオブジェクトの情報がログとして表示されます。このシンプルな例を通じて、カスタムイベントを使用してUnityでのオブジェクト間のインタラクションをどのように実装するかを理解できます。
ディスカッション
コメント一覧
まだ、コメントがありません