Designed to be easy to use, extendable and optimized where it's possible.
An EventBus is a mechanism that allows different components to communicate with each other without knowing about each other. A component can send an Event to the EventBus without knowing who will pick it up or how many others will pick it up.
- interface based
- listeners priority sorting
- ability to send functions and messages
- local buses creation with the ability to subscribe as a listener
- timeline compatibility
- filtered messaging
- expandability
// subscriber class definition public class SampleListener : Subscriber, IListener<GlobalEvent>, // react on GlobalEvent(Enum) messages IListener<IEvent<GlobalEvent>>, // react on IEvent<GlobalEvent> messages IDamageTaker, IHandle<IDamageTaker> // provide IDamageTaker interface for invokation// send enum event to the GlobalBus GlobalBus.Send(GlobalEvent.Activate); // send IEvent<GlobalEvent> with custom data GlobalBus.SendEvent(GlobalEvent.Activate, 1f); // send action to the GlobalBus GlobalBus.SendAction<IDamageTaker>(damageTaker => damageTaker.TakeDamage(1)); // send with filtration GlobalBus.Send(GlobalEvent.Activate, sub => sub is Unit);// none MonoBehaviour subscriber public class SampleListenerClass : ISubscriberOptions, // optional priority and name options IListener<GlobalEvent>, IDamageTaker, IHandle<IDamageTaker> { // react on sent data public void React(in GlobalEvent e) { if (e == GlobalEvent.GameStart) { // do something } } // provide interface for method invocation public void IDamageTaker.Damage(int dmg) { // do something } // subscriber extra options public string Name => name; // name for debugging purposes public int Priority => 1; // execution order related to other subscribed listeners // subscription methods (bus can be any, in example used global bus singleton) public void Subscribe() => GlobalBus.Subscribe(this); public void Unsubscribe() => GlobalBus.Unsubscribe(this); }Through Unity Package Manager git URL:
https://github.com/NullTale/UnityEventBus.git Or copy-paste somewhere inside your project Assets folder.
On OnEnable event Listener will connect to the desired bus and will start receiving messages from it.
using UnityEngine; using UnityEventBus; // same as SimpleListener : Subscriber, IListener<string> public class SimpleListener : Listener<string> { public override void React(in string e) { Debug.Log(e); } }In the unity editor, you can set up the behavior in detail. Such as subscription targets and priority.
Note: Lower priority triggers first, highest last, equal invokes in order of subscription
To create your custom listener you need to implement at least one IListener<> interface and subscribe to the desired bus.
Note: Listener can have any number of IListener<> interfaces.
using UnityEngine; using UnityEventBus; public class SimpleListener : MonoBehaviour, IListener<string> { private void Start() { // somewhere in code... // send string event to the global bus GlobalBus.Send<string>("String event"); } // subscribe to the global bus private void OnEnable() { GlobalBus.Subscribe(this); } // unsubscribe from the global bus private void OnDisable() { GlobalBus.UnSubscribe(this); } // react to an event public void React(in string e) { Debug.Log(e); } }You can also implement ISubscriberOptions interface to setup debug name and listener priority.
public class SimpleListener : MonoBehaviour, IListener<string>, ISubscriberOptions { public string Name => name; public int Priority => 1;To create a local bus, you need to derive it from the EventBusBase class
Note: Event bus can be subscribed to the other buses like a listener, using Subscribe and UnSubscribe methods.
using UnityEngine; using UnityEventBus; public class Unit : EventBusBase { private void Start() { // send event to this this.Send("String event"); } }You can also derive it from the EventBus class to configure auto-subscription and priority.
Note: If EventBus implements any Subscribers interfaces, they will be automatically subscribed to it.
public class Unit : EventBusSometimes it can be more convenient to look at listeners as a set of interfaces, the SendAction method extension is used for this. For an object to be an action target it must execute an interface IHandle<> with the interface type it provides.
public class Unit : EventBus { [ContextMenu("Heal Action")] public void Heal() { // send invoke heal action on the IUnitHP interface this.SendAction<IUnitHP>(hp => hp.Heal(1)); } }public interface IUnitHP { void Heal(int val); } // implement IHandle<IUnitHP> interface to be an action target public class UnitHP : Subscriber, IUnitHP, IHandle<IUnitHP> { public int HP = 2; public void Heal(int val) { HP += val; } }Event is a message that contains keys and optional data. To send an Event, the SendEvent extension method is used. To receive events must be implemented IListener<IEvent<TEventKey>> interface, where TEventKey is a key of events, which listener wants to react.
using UnityEngine; using UnityEventBus; // unit derived from the EventBus class, he is receives events and propagate them to subscribers public class Unit : EventBusBase { private void Start() { // send creation event without data this.SendEvent(UnitEvent.Created); } [ContextMenu("Damage")] public void DamageSelf() { // send event with int data this.SendEvent(UnitEvent.Damage, 1); } [ContextMenu("Heal")] public void HealSelf() { this.SendEvent(UnitEvent.Heal, 1); } } // unit event keys public enum UnitEvent { Created, Damage, Heal }using UnityEngine; using UnityEventBus; // OnEnable will subscribe to the unit and start to listen messages // same as UnitHP : EventListener<UnitEvent> public class UnitHP : Subscriber, IListener<IEvent<UnitEvent>> { public int HP = 2; // reacts to UnitEvents public override void React(in IEvent<UnitEvent> e) { switch (e.Key) { // event with damage or heal key always containts int data case UnitEvent.Damage: HP -= e.GetData<int>(); break; case UnitEvent.Heal: HP += e.GetData<int>(); break; case UnitEvent.Created: break; } } }Also multiple data can be sent through an event.
// send multiple data SendEvent(UnitEvent.Created, 1, 0.2f, this);// get multiple data var (n, f, unit) = e.GetData<int, float, Unit>(); // or if (e.TryGetData(out int n, out float f, out Unit unit)) { // do something with data }The small extension that allow you to use Timeline.SignalAsset as messages in order to.
React to signals.
Send signals from the director,
or through script or MonoBehaviour.
Request is needed to get permission for something from another subscriber. Request works just like Event, contains key and optional data, but it can be either approved or ignored and he will propagate until first approval. It is in fact a usable event with the only difference that you can get the result of execution. The SendRequest method extension is used to send a Request.
public class Unit : EventBus { [ContextMenu("HealRequest ")] public void HealRequest() { if (this.SendRequest(UnitEvent.Heal, 1)) { // request was approved // do something, play animation or implement logic } } }public class UnitHP : Subscriber, IListener<IRequest<UnitEvent>> { public int HPMax = 2; public int HP = 2; public void React(in IRequest<UnitEvent> e) { switch (e.Key) { case UnitEvent.Heal: { // if can heal, approve heal request var heal = e.GetData<int>(); if (heal > 0 && HP < HPMax) { HP += heal; e.Approve(); } } break; } } }





