📜 ⬆️ ⬇️

Broadcast Event Messaging in Unity3D

When developing games, quite often there is a need to build a system for broadcasting messages. Suppose you want to make sure that at that moment when a character controlled by a player enters a certain zone or performs a certain action, all objects interested in this will receive a notification. If possible, this notification should contain information about the event. In this article, I offer you one of the possible ways to build such a system. The above system is based on the Unity3D EventSystem .

Starting with version 4.6, the UI System is included in Unity3D, which greatly simplifies the process of creating a UI. In addition, it is an open source project. At the heart of this system are two very important components - EventSystem and InputModules , allowing to receive and process events. In fact, InputModules are normal components. They are the heirs of UIBehaviour, which in turn inherits MonoBehaviour and contain the logic of event processing from the EventSystem.
Sending an event to a specific GameObject is done by calling the ExecuteEvents.Execute () method. The method definition is as follows:

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

When calling this method, as parameters you must pass a reference to a GameObject in the list of associated components of which the InpuModule implementing interface T or the inheriting interface T must be present. If there are several such components, they will all be called in turn.
As you can see, to send an event, you must have a link to the target GameObject , which is not suitable for broadcasting.
The solution to this problem can be a collection containing a list of GameObjects with attached InputModules capable of handling broadcast events.

 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); } } 

The BroadcastInputModule class serves as the base class for the event handler modules. Its main task is to register the module in this collection.
Let's move on to creating a module that will respond to a global event, which we conditionally call " 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() { } } 

This component must be added to all GameObjects interested in receiving the SomethingHappened event. The ISomethingHappenedEventHandler interface looks like this:

 public interface ISomethingHappenedEventHandler : IEventSystemHandler { void OnSomethigHappened(SomethingHappenedEventData data); } 

A collection that stores handlers can be quite simple, for example:

 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) { . . . } } 

In a real game, perhaps, this collection should contain WeakReferences instead of direct links to GameObjects, it already depends on the requirements.
The last element is the BroadcastExecuteEvents class:

 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); } } } 

As can be seen from its definition, it is just a wrapper on ExecuteEvents and performs only one task - the selection of suitable handlers for the specified event and their call.

Now you can make a broadcast event like this:

 BroadcastExecuteEvents.Execute<ISomethingHappenedEventHandler>(null, (i, d) => i.OnSomethigHappened(new SomethingHappenedEventData())); 


The source code for the article can be picked up from github.com/rumyancevpavel/BroadcastMessaging

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


All Articles