ゲームを開発するとき、非常に多くの場合、メッセージをブロードキャストするためのシステムを構築する必要があります。 プレイヤーがコントロールするキャラクターが特定のゾーンに入ったとき、または特定のアクションを実行したときに、これに関心のあるすべてのオブジェクトが通知を受け取るようにしたいとします。 可能であれば、この通知にはイベントに関する情報を含める必要があります。 この記事では、このようなシステムを構築するための可能な方法の1つに注目します。 指定されたシステムは
Unity3D EventSystemに基づいています。
バージョン4.6以降、Unity3Dには
UI Systemが含まれ、
UIの作成プロセスが大幅に簡素化されています。 さらに、それはオープンソースプロジェクトです。 このシステムの中心には、
EventSystemと
InputModulesという 2つの非常に重要なコンポーネントがあり、これらを使用してイベントを受信および処理できます。 本質的に、
InputModuleは通常のコンポーネントです。 これらは
UIBehaviourの相続人であり、
UIBehaviourは
MonoBehaviourを継承し、EventSystemからのイベントを処理するためのロジックを含んでいます。
イベントは、
ExecuteEvents.Execute()メソッドを呼び出すことにより、特定の
GameObjectにディスパッチされます。 メソッド定義は次のとおりです。
public static bool Execute<T>(GameObject target, BaseEventData data, EventFunction<T> functor) where T : IEventSystemHandler;
このメソッドを呼び出すとき、
InpuModuleが
Tインターフェースまたは
T継承インターフェースを実装する関連コンポーネントのリストのパラメーターとして
GameObjectへのリンクを渡す必要があります。 そのようなコンポーネントが複数ある場合、それらすべてが順番に呼び出されます。
ご覧のとおり、イベントを送信するには、ブロードキャストに適していないターゲット
GameObjectへのリンクが必要です。
この問題の解決策は、ブロードキャストイベントを処理できるInputModuleがアタッチされたGameObjectsのリストを含むコレクションです。
public abstract class BroadcastInputModule<TEventType> : BaseInputModule where TEventType : IEventSystemHandler { protected override void Awake() { base.Awake(); BroadcastReceivers.RegisterBroadcastReceiver<TEventType>(gameObject); } protected override void OnDestroy() { base.OnDestroy(); BroadcastReceivers.UnregisterBroadcastReceiver<TEventType>(gameObject); } }
BroadcastInputModuleクラスは、ブロードキャストイベントハンドラーモジュールの基本クラスです。 その主なタスクは、このコレクションにモジュールを登録することです。
グローバルイベントに応答するモジュールの作成に移りましょう。このイベントを任意に「
SomethingHappened 」と呼びます。
[AddComponentMenu("Event/Something Happened Input Module")] public class SomethingHappenedInputModule : BroadcastInputModule<ISomethingHappenedEventHandler>, ISomethingHappenedEventHandler { public void OnSomethigHappened(SomethingHappenedEventData data) { Debug.Log("SomethingHappenedInputModule::OnSomethigHappened()"); } public override void Process() { } }
このコンポーネントは、
SomethingHappenedイベントの受信に関心があるすべてのGameObjectsに追加する必要があります。
ISomethingHappenedEventHandlerインターフェイスは次のとおりです。
public interface ISomethingHappenedEventHandler : IEventSystemHandler { void OnSomethigHappened(SomethingHappenedEventData data); }
ハンドラーのコレクションは、次のように非常に単純にすることができます。
public static class BroadcastReceivers { private static readonly IDictionary<Type, IList<GameObject>> BroadcstReceivers = new Dictionary<Type, IList<GameObject>>(); public static IList<GameObject> GetHandlersForEvent<TEventType>() where TEventType : IEventSystemHandler { if (!BroadcstReceivers.ContainsKey(typeof (TEventType))) { return null; } return BroadcstReceivers[typeof (TEventType)]; } public static void RegisterBroadcastReceiver<TEventType>(GameObject go) where TEventType : IEventSystemHandler { if (BroadcstReceivers.ContainsKey(typeof(TEventType))) { BroadcstReceivers[typeof(TEventType)].Add(go); } else { BroadcstReceivers.Add(typeof(TEventType), new List<GameObject>()); BroadcstReceivers[typeof(TEventType)].Add(go); } } public static void UnregisterBroadcastReceiver<TEventType>(GameObject go) { . . . } }
実際のゲームでは、おそらくこのコレクションにGameObjectsへの直接リンクではなくWeakReferencesを含める必要があります。これは既に要件に依存しています。
最後の要素は
BroadcastExecuteEventsクラスです。
public static class BroadcastExecuteEvents { public static void Execute<T>(BaseEventData eventData, ExecuteEvents.EventFunction<T> functor) where T : IEventSystemHandler { var handlers = BroadcastReceivers.GetHandlersForEvent<T>(); if (handlers == null) return; foreach (var handler in handlers) { ExecuteEvents.Execute<T>(handler, eventData, functor); } } }
定義からわかるように、これは
ExecuteEventsの単なるラッパーで
あり 、1つのタスクのみを実行します。指定されたイベントに適切なハンドラーを選択して呼び出します。
これで、次のようにイベントをブロードキャストできます。
BroadcastExecuteEvents.Execute<ISomethingHappenedEventHandler>(null, (i, d) => i.OnSomethigHappened(new SomethingHappenedEventData()));
この記事のソースコードは、
github.com / rumyancevpavel / BroadcastMessagingから
取得できます。