Unity3Dでのイベントメッセージングのブロードキャスト

ゲームを開発するとき、非常に多くの場合、メッセージをブロードキャストするためのシステムを構築する必要があります。 プレイヤーがコントロールするキャラクターが特定のゾーンに入ったとき、または特定のアクションを実行したときに、これに関心のあるすべてのオブジェクトが通知を受け取るようにしたいとします。 可能であれば、この通知にはイベントに関する情報を含める必要があります。 この記事では、このようなシステムを構築するための可能な方法の1つに注目します。 指定されたシステムはUnity3D EventSystemに基づいています。

バージョン4.6以降、Unity3DにはUI Systemが含まれ、 UIの作成プロセスが大幅に簡素化されています。 さらに、それはオープンソースプロジェクトです。 このシステムの中心には、 EventSystemInputModulesという 2つの非常に重要なコンポーネントがあり、これらを使用してイベントを受信および処理できます。 本質的に、 InputModuleは通常のコンポーネントです。 これらはUIBehaviourの相続人であり、 UIBehaviourMonoBehaviourを継承し、EventSystemからのイベントを処理するためのロジックを含んでいます。
イベントは、 ExecuteEvents.Execute()メソッドを呼び出すことにより、特定のGameObjectにディスパッチされます。 メソッド定義は次のとおりです。

public static bool Execute<T>(GameObject target, BaseEventData data, EventFunction<T> functor) where T : IEventSystemHandler; 

このメソッドを呼び出すとき、 InpuModuleTインターフェースまたは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から取得できます。

Source: https://habr.com/ru/post/J254239/


All Articles