Discovering Unity EventManager

An official pattern for managing events and state in Unity.

In going through a number of Unity tutorials awhile ago, I quickly determined that the common practice of sharing state between game objects through direct reference was going to be unsustainable (leading to spagetti-code).

At that time, my search for standard state management solutions in Unity turned up precious little. So, I turned to my web development background and built a state management solution using the Flux pattern; in particular modeled on Redux.

More recently, however, I bumped into the answer that I was originally looking for; an official solution for scalable state management in Unity.

Went ahead and wrote a simple application using this approach (with EventManager) and thought to share my experience.

The final solution is available for download.

The Application

The application consists of a ball, an arena (floor and four walls), a pillar in the middle of the arena, a score indicator, and a start button. The game opens with the ball being stationary. Pressing the Start button sends the ball moving. Each time the ball hits the pillar the score indicator is incremented by one.

Breaking down this application into events and state, we have:

  • The START event; initiated by the Start game object, observed by the Start and Ball game objects
  • The COLLISION event; initiated by the Pillar game object, observed by the Score game object
  • The score (integer) state; updated along-side of the COLLISION event, consumed by the Score game object

EventManager

The heavy-lifting is done in the EventManager script (on the EventManager game object). The official documentation provides an explanation of the construction of this script; the usage is as follows:

EventManager.StartListening(string eventName, UnityAction listener)

Use when a game object is enabled (OnEnable method); once called, when events of type eventName occur, the listener (a method of the game object) is called.

EventManager.StopListening(string eventName, UnityAction listener)

Use when a game object is disabled (OnDisable method); once called, will stop the behavior enabled by StartListening

EventManager.TriggerEvent(string eventName)

Use to trigger an event of type eventName.

Global

Because these events do not carry any payload, we need an alternative way of sharing state (global) between game objects. The simplest solution is to create a public static class with public static fields.

Assets / Global.cs

Listening Example

The ball observes the START event.

Assets / Ball.cs

Triggering Example

The start button triggers START events; and also observes START events.

Assets / Start.cs

Triggering Example with State Change

The pillar updates the score and triggers COLLISION events.

Assets / Pillar.cs

Suggested Improvements

Just looking at this simple example; there are some problems:

  • Having to both update the score and triggering COLLISION events separately in the pillar game object is fragile, i.e., it would be easy to make a mistake to only do only one of the two
  • It is difficult to ascertain which events exists throughout the application, e.g., one would have to search the code to find all the calls to TriggerEvent to determine the event types.

One solution is to create public static methods on the Global class to trigger events; i.e., never do you directly call TriggerEvent from a game object.

Wrap Up

While I am a bit frustrated that it took this long to find this event and state management pattern, I am happy to have found it now. Hope you likewise find this pattern useful.

Broad infrastructure, development, and soft-skill background

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store