Broadcast Event Messaging in Unity3D

Often there is a need to build a system that broadcast messages. Suppose you want to make sure that at the moment when a character controlled by the player, enters into a certain area, or if you want it to perform certain actions, all interested in the actions object have been notified. If possible, the notice must carry the information about the event. In this article, I present to you one of the possible ways of constructing such a system. The above system is based on Unity3D EventSystem.

Starting with version 4.6 of the Unity3D enabled UI System, greatly simplifies the process of creating the UI. Moreover, it is an Open Source project. The heart of this system is based on two very important components - EventSystem and InputModules,witch can receive and handle events. In fact, InputModules - this conventional components. They are the heirs UIBehaviour which in turn inherits MonoBehaviour and contain logic processing events from EventSystem.

Sending events defined GameObject done by calling Execute Events.Execute (). Determining the method is as follows:

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

By calling this method, as the parameters you need to pass a reference to the GameObject in the list of associated components which must be present InpuModule T implements the interface or interface inherits from T. If such components would be a few, they will be called in turn.
As you can see when , sending eventseach event must - have  a reference to the target GameObject, which is not suitable for broadcast.
The solution to this problem could serve as a collection containing a list of GameObjects with attached InputModules capable of processing 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);
    }
}

Class Broadcast Input Module serves as a base for modules that handles broadcast events. Its main task is to register the module in this collection.
Let's move on to creating a module that will respond to the global event, which will be called conditionally "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 should be added to all Game Objects interested in receiving events SomethingHappened. ISomethingHappenedEventHandler interface is as follows:

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

Collection stores handlers can be quite simple, like this:

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 Weak References instead of direct links to GameObjects, it depends on the requirements.
The final element is the class 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);
        }
    }
}

As can be seen from its definition, it is just a wrapper over ExecuteEvents and perform only one task - to select something suitable for the specified event and challenge.

Now make a broadcast sending events:

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

The source code to the article: http://github.com/rumyancevpavel/BroadcastMessaging

 

 

 

All data posted on the site represents accessible information that can be browsed and downloaded for free from the web.

 

http://habrahabr.ru/post/254239/

 

User replies

No replies yet