子オブジェクトのイベント処理実装
以下は、子オブジェクト毎のイベント処理の実装手法を、引数なし/引数ありの両パターンとして、以下の3つの方式(個別スクリプト方式、親通知方式、UnityEvent方式)の資料になります。
次の資料の続きになります
目次
1. 個別スクリプト方式
1-1. 引数なしの実装
各子オブジェクトに専用のスクリプトをアタッチし、イベント発生時に単にログ出力などの固定処理を実装する例です。
using UnityEngine;
public class ChildColliderHandler_NoArgs : MonoBehaviour
{
void OnTriggerEnter(Collider other)
{
Debug.Log($"{gameObject.name} で Trigger イベント発生:{other.gameObject.name}");
// 引数なしの処理(固定の処理を実装)
}
void OnCollisionEnter(Collision collision)
{
Debug.Log($"{gameObject.name} で Collision イベント発生:{collision.gameObject.name}");
// 引数なしの処理(固定の処理を実装)
}
}
メリット・デメリット(引数なし)
- メリット
- 実装がシンプルで分かりやすい
- 各子オブジェクトで直接制御できる
- デメリット
- イベント詳細(相手情報など)を活用できない
- 変更が必要な際、各スクリプトの修正が必要
1-2. 引数ありの実装
イベント発生時に、引数としてイベント情報(例:衝突相手のColliderやCollision情報)を利用して処理を行う例です。
using UnityEngine;
public class ChildColliderHandler_WithArgs : MonoBehaviour
{
void OnTriggerEnter(Collider other)
{
HandleTriggerEvent(other);
}
void OnCollisionEnter(Collision collision)
{
HandleCollisionEvent(collision);
}
// Triggerイベントの引数付きハンドラ
private void HandleTriggerEvent(Collider other)
{
Debug.Log($"{gameObject.name} で Trigger イベント発生:相手は {other.gameObject.name}");
// 引数(other)を用いた処理を実装
}
// Collisionイベントの引数付きハンドラ
private void HandleCollisionEvent(Collision collision)
{
Debug.Log($"{gameObject.name} で Collision イベント発生:相手は {collision.gameObject.name}");
// 引数(collision)を用いた処理を実装
}
}
メリット・デメリット(引数あり)
- メリット
- イベント詳細情報を柔軟に利用できる
- 各子オブジェクトでイベントの発生状況を正確に把握可能
- デメリット
- 実装が各スクリプトに分散するため、共通処理の変更が煩雑になる可能性がある
2. 親通知方式
子オブジェクト側でイベントが発生した際に、親オブジェクトへ通知し、親側で一元管理・分岐処理を実装する方式です。
2-1. 引数なしの実装
子側スクリプト
using UnityEngine;
public class ChildColliderNotifier_NoArgs : MonoBehaviour
{
void OnTriggerEnter(Collider other)
{
// 引数なしで親に通知
transform.parent.SendMessage("OnChildTriggerEvent_NoArgs", gameObject, SendMessageOptions.DontRequireReceiver);
}
void OnCollisionEnter(Collision collision)
{
// 引数なしで親に通知
transform.parent.SendMessage("OnChildCollisionEvent_NoArgs", gameObject, SendMessageOptions.DontRequireReceiver);
}
}
親側スクリプト
using UnityEngine;
public class ParentEventManager_NoArgs : MonoBehaviour
{
void OnChildTriggerEvent_NoArgs(GameObject child)
{
Debug.Log($"親で受信(引数なし):{child.name} から Trigger イベント");
// 共通処理または子ごとの処理分岐を実装
}
void OnChildCollisionEvent_NoArgs(GameObject child)
{
Debug.Log($"親で受信(引数なし):{child.name} から Collision イベント");
// 共通処理または子ごとの処理分岐を実装
}
}
メリット・デメリット(引数なし)
- メリット
- 親側で一元管理でき、全体の流れが把握しやすい
- 実装がシンプル
- デメリット
- イベントの詳細情報が通知されないため、処理内容が限定的
2-2. 引数ありの実装
カスタムイベントデータクラス
using UnityEngine;
public class ChildEventInfo
{
public GameObject Child; // イベント発生元の子オブジェクト
public GameObject Other; // 衝突相手のオブジェクト(ColliderまたはCollisionの相手)
public string EventType; // "Trigger" または "Collision"
// 必要に応じて、追加情報も持たせる
}
子側スクリプト
using UnityEngine;
public class ChildColliderNotifier_WithArgs : MonoBehaviour
{
void OnTriggerEnter(Collider other)
{
ChildEventInfo info = new ChildEventInfo {
Child = gameObject,
Other = other.gameObject,
EventType = "Trigger"
};
transform.parent.SendMessage("OnChildEvent_WithArgs", info, SendMessageOptions.DontRequireReceiver);
}
void OnCollisionEnter(Collision collision)
{
ChildEventInfo info = new ChildEventInfo {
Child = gameObject,
Other = collision.gameObject,
EventType = "Collision"
};
transform.parent.SendMessage("OnChildEvent_WithArgs", info, SendMessageOptions.DontRequireReceiver);
}
}
親側スクリプト
using UnityEngine;
public class ParentEventManager_WithArgs : MonoBehaviour
{
void OnChildEvent_WithArgs(ChildEventInfo info)
{
if (info.EventType == "Trigger")
{
Debug.Log($"親で受信(引数あり):{info.Child.name} から Trigger イベント(相手:{info.Other.name})");
// Triggerイベント用の詳細処理
}
else if (info.EventType == "Collision")
{
Debug.Log($"親で受信(引数あり):{info.Child.name} から Collision イベント(相手:{info.Other.name})");
// Collisionイベント用の詳細処理
}
}
}
メリット・デメリット(引数あり)
- メリット
- イベント詳細情報を親側で一元管理できるため、柔軟な共通処理や分岐が可能
- カスタムクラスで複数の引数をまとめて渡せる
- デメリット
- SendMessageは型安全性に欠け、パフォーマンスやデバッグが難しい場合がある
- 親側での分岐処理が複雑になる可能性がある
3. UnityEvent方式
UnityEventを利用することで、Inspector上から直感的にイベントの割り当てが可能となり、プログラマー以外のメンバーも設定可能な方式です。
3-1. 引数なしの実装
using UnityEngine;
using UnityEngine.Events;
public class ChildEventTrigger_NoArgs : MonoBehaviour
{
[Header("UnityEvent設定(引数なし)")]
public UnityEvent OnChildTrigger;
public UnityEvent OnChildCollision;
void OnTriggerEnter(Collider other)
{
Debug.Log($"{gameObject.name} で Trigger 発生:{other.gameObject.name}");
OnChildTrigger?.Invoke();
}
void OnCollisionEnter(Collision collision)
{
Debug.Log($"{gameObject.name} で Collision 発生:{collision.gameObject.name}");
OnChildCollision?.Invoke();
}
}
メリット・デメリット(引数なし)
- メリット
- エディタ上で直感的にメソッドをドラッグ&ドロップで割り当て可能
- シンプルな実装で、柔軟性に優れる
- デメリット
- イベント詳細情報(例:衝突相手など)を受け取ることができない
3-2. 引数ありの実装
事前定義:パラメータ付きUnityEventクラス
using UnityEngine;
using UnityEngine.Events;
[System.Serializable]
public class ColliderEvent : UnityEvent<Collider> { }
[System.Serializable]
public class CollisionEvent : UnityEvent<Collision> { }
子側スクリプト
using UnityEngine;
using UnityEngine.Events;
public class ChildEventTrigger_WithArgs : MonoBehaviour
{
[Header("UnityEvent設定(引数あり)")]
// Triggerイベント用(引数:Collider)
public ColliderEvent OnChildTrigger;
// Collisionイベント用(引数:Collision)
public CollisionEvent OnChildCollision;
void OnTriggerEnter(Collider other)
{
Debug.Log($"{gameObject.name} で Trigger 発生:{other.gameObject.name}");
OnChildTrigger?.Invoke(other);
}
void OnCollisionEnter(Collision collision)
{
Debug.Log($"{gameObject.name} で Collision 発生:{collision.gameObject.name}");
OnChildCollision?.Invoke(collision);
}
}
インスペクター設定例
- 各子オブジェクトに
ChildEventTrigger_WithArgs
をアタッチ - Inspector上の「On Child Trigger」や「On Child Collision」に、引数(ColliderまたはCollision型)を受け取る対象メソッドをドラッグ&ドロップで設定
メリット・デメリット(引数あり)
- メリット
- 引数付きイベントをエディタ上で柔軟に設定可能
- 非プログラマーでもイベントの割り当てが直感的に行える
- 再利用性、保守性が高い
- デメリット
- 大量に使用するとシリアライズのオーバーヘッドが増加する可能性
- 複雑なロジックにはコードで直接制御したほうが明確な場合がある
まとめ
- 個別スクリプト方式
- 引数なし:シンプルな実装で各子ごとの固定処理に最適
- 引数あり:イベント詳細を活用し、柔軟な個別処理を実装可能
- 親通知方式
- 引数なし:親で一元管理する際のシンプルな通知方法
- 引数あり:カスタムデータクラスを用いて、詳細情報を親側で一括管理可能
- UnityEvent方式
- 引数なし:エディタ上で直感的に設定でき、シンプルな実装が可能
- 引数あり:パラメータ付きUnityEventにより、柔軟かつ再利用性の高いイベント管理を実現
各手法は、プロジェクトの要件やチームの運用体制に合わせて選択してください。どの方式も、引数の有無を含めた柔軟なイベント処理が実現でき、シーン内の子オブジェクト毎の挙動を細かく制御することが可能です。
ディスカッション
コメント一覧
まだ、コメントがありません