I think this is a good idea? There are other event buses out there so I don’t believe it’s an anti-pattern. I used a visual scripting tool that used events in a similar way and I find it a natural way of thinking about events, while still using the standards for events, such as including the sender and an EventArgs derived data package. With the difference being you can choose which side knows about whom. In some cases it can be easier to have the sender know about the target instead of the subscriber having to be sent a reference or managing who the subscriber needs to be listening to if multiple or different senders are to be introduced. The subscriber can just say listening for event on itself, or a parent/root hub, or globally. If you don’t like using strings for event names, there are many work arounds for that.
An event does not have to be declared in all your scripts. “Events” are called to the EventManager just by calling Publish. If someone is listening, an event (delegate) exists with the subscribers that will be called. If not, nothing happens. All events, subscribing, and invoking stay inside the manager wrapped by methods.
Subscriber Example
private void OnEnable() => EventManager.Subscribe<RebindingProcessEventArgs>("TestEvent", EventTarget, DoTheThing);
private void OnDisable() => EventManager.Unsubscribe<RebindingProcessEventArgs>("TestEvent", EventTarget, DoTheThing);
public void DoTheThing(object sender, RebindingProcessEventArgs test) {
Debug.Log($"DoTheThing has been called.{gameObject.name} {test.Message}");
}
Publisher Example
public string EventName = "TestEvent";
public GameObject EventTarget;
public string EventMessage = "This has been a test message. Beep! Beeeeeep! Beeeeeep!";
[BareButton("Publish An Event")]
public void PublishEvent() {
var eventArgs = new RebindingProcessEventArgs(EventMessage);
EventManager.Publish(this, EventName, EventTarget, eventArgs);
}
-
Subscriber listening for event on itself as target.
-
Subscriber listening for event on parent, manager or other as target.
-
Sender sending to self as target as a hub.
-
Sender sending to a target.
-
Sender sending to global (ignoring target, could make testing easier).
-
Manager component sending test event manually configured in inspector and button push.
-
Subscriber and sender can set null target to form a universal group for the regular Publish call (and not the global call).
This system took a good deal of noodling, and research on typical event bus patterns, but in the end, ends up being relatively simple. It doesn’t really obfuscate what is happening because events are published differently with a static publish method. A dictionary of delegates is kept for all references within the manager and scripts just sub/unsub. Multiple senders, different senders doesn’t matter. Maybe you could say there is some blending with messages, or regular method usage. But it’s another way of organizing intention as well. Which is a lot of what events are structured around in the first place. And now here adding flexibility, testing, debugging… I’m curious to get some feedback.
You can find the Event Manager here.