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 the moment when the character controlled by the player enters a certain zone or performs a certain action, all objects interested in this receive a notification. If possible, this notification should contain information about the event. In this article, I bring to your attention one of the possible ways to build such a system. The given system is based on the Unity3D EventSystem .

    Starting with version 4.6, Unity3D includes a UI System , 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 essence, InputModules are ordinary components. They are the heirs of UIBehaviour, which in turn inherits MonoBehaviour and contains the logic for processing events from the EventSystem.
    An event is dispatched to a specific GameObject by calling the ExecuteEvents.Execute () method . The method definition is as follows:

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

    Calling this method, you must pass a link to GameObject as a parameter in the list of associated components of which InpuModule implements the T interface or the T inheritor interface . If there are several such components, all of them will 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.
    A 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 : BaseInputModule
        where TEventType : IEventSystemHandler
    {
        protected override void Awake()
        {
            base.Awake();
            BroadcastReceivers.RegisterBroadcastReceiver(gameObject);
        }
        protected override void OnDestroy()
        {
            base.OnDestroy();
            BroadcastReceivers.UnregisterBroadcastReceiver(gameObject);
        }
    }
    

    The BroadcastInputModule class is the base class for broadcast 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 will arbitrarily call " SomethingHappened ".

    [AddComponentMenu("Event/Something Happened Input Module")]
    public class SomethingHappenedInputModule
        : BroadcastInputModule, ISomethingHappenedEventHandler
    {
        public void OnSomethigHappened(SomethingHappenedEventData data)
        {
            Debug.Log("SomethingHappenedInputModule::OnSomethigHappened()");
        }
        public override void Process()
        {
        }
    }
    

    This component should be added to all GameObjects interested in receiving the SomethingHappened event . The ISomethingHappenedEventHandler interface is as follows:

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

    A collection of handlers can be quite simple, like this:

    public static class BroadcastReceivers
    {
        private static readonly IDictionary>
            BroadcstReceivers = new Dictionary>();
        public static IList GetHandlersForEvent()
            where TEventType : IEventSystemHandler
        {
            if (!BroadcstReceivers.ContainsKey(typeof (TEventType)))
            {
                return null;
            }
            return BroadcstReceivers[typeof (TEventType)];
        }
        public static void RegisterBroadcastReceiver(GameObject go)
            where TEventType : IEventSystemHandler
        {
            if (BroadcstReceivers.ContainsKey(typeof(TEventType)))
            {
                BroadcstReceivers[typeof(TEventType)].Add(go);
            }
            else
            {
                BroadcstReceivers.Add(typeof(TEventType), new List());
                BroadcstReceivers[typeof(TEventType)].Add(go);
            }
        }
        public static void UnregisterBroadcastReceiver(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 final element is the BroadcastExecuteEvents class :

    public static class BroadcastExecuteEvents
    {
        public static void Execute(BaseEventData eventData, ExecuteEvents.EventFunction functor) 
            where T : IEventSystemHandler
        {
            var handlers = BroadcastReceivers.GetHandlersForEvent();
            if (handlers == null) return;
            foreach (var handler in handlers)
            {
                ExecuteEvents.Execute(handler, eventData, functor);
            }
        }
    }
    

    As you can see from its definition, it is just a wrapper over ExecuteEvents and performs only one task - selecting the appropriate handlers for the specified event and calling them.

    Now you can broadcast the event as follows:

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


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

    Also popular now: