CODEX
RTS Interlude #1: Introducing an event system (Unity/C#)
On with our RTS project — in this interlude, we’re going to talk about events!
⬅️ Tutorial #3: Setting up in-game resources | TOC | Tutorial #4: Selecting units ➡️
📕 Get the ebook and bonus material on Gumroad! 🚀 Find the code of this tutorial series on my Github!
So far in this series, we’ve set the scene for several big features and used a little palette of tools that Unity and C# provide: the new UI system, raycasting, game object instantiation, resources loading, material switching, global variables and basic data encapsulation… There is however something fundamental in video games we haven’t yet talked about: events.

Overall, programs can follow various paradigms in terms of instructions execution, data layout, components hierarchy and communication, etc. In video games, it is very common to have an update loop that runs continuously (more or less every rendering frame) and checks with all the systems in the game if they need to do or return something. In Unity, this built-in structure is visible through the Update() method that's available in every MonoBehavior-derived class.
To interact with all those systems and react to user inputs, most video games rely on events. Today, we are going to implement a basic event system and use it to improve how we update the game resource texts in the UI when placing a building.
Why use events?
The funny thing about object-oriented programming (or OOP) is that, at its core, it wasn’t meant to be about objects primarily. Its creator, Alan Kay, had very different things in mind for it compared to what it’s become — most famously, he once said:
I invented the term object oriented, and I can tell you that C++ wasn’t what I had in mind.
More specifically, Kay’s background in biology lead him to design a way of programming based on autonomous entities communicating between them via messages. Objects would be individual cells in a big network, properly encapsulated with “local retention”, without all the porosity we usually see in OOP these days. Hence the idea of using events as a tool for this messaging and for keeping objects separate “organisms”.
A big plus when using an event system is that our emitters broadcast their events to all other components at the same time. For example, you could send a single event and have it caught by the UI system, the audio system, a data manager… Virtually all parts of your projects can react to an event and it’s very easy to add or remove those listeners.
All of this brings us to the essential reason event systems are so great: modularity. Whenever your project starts to grow in complexity, you run the risk of having all of your components too entangled together — you basically end up with one big mix of lots of little things that you can’t separate anymore. At that point, you don’t have a network of individual organisms but one big organism with a somewhat Frankenstein body. In OOP, this can happen particularly quickly: think of how easy it was to add a reference to our UIManager in a script and call it to update some display on the screen. Although it sounds great at first, it's actually a pattern that slowly drags your code down because you are tying all of your systems together and creating unnecessary dependencies.
The way an event system handles this issue is by relying on a “fire-and-forget” mechanism. Roughly speaking, this means that when an emitter sends an event, it doesn’t care about whether or not there are listeners to catch it, and if they do catch it properly. Its only job is to send the event. Then, it’s up to the listeners to be up and ready. The advantage of this philosophy is that everything is decoupled and therefore more robust and easy to unit test.
Say you want to check that your mechanics for updating the player health works well. In a naive setting, you’d probably have a reference in your player manager script to your UI system so that whenever the player’s HP are modified, the healthbar shown on the screen shrinks or grows accordingly. The direct consequence of this link is that if you create a new empty scene and bring in your player manager, you’ll have a “missing reference” for your UI manager. Therefore you’ll have to import this one as well. And chances are that this UI manager relies on your global game manager class; so you’ll have to import this class, too. And so on…
Thanks to events, you break the connection between the player manager and the UI system. Instead, your player manager will simply emit an event that can be caught by the UI system if it’s there, or ignored otherwise.
Creating the EventManager class
To kickstart this feature, we can draw inspiration from the official Unity’s live training on how to design a simple messaging system. The EventManager they create throughout the session holds a C# Dictionary of events keyed by names (as strings) and it uses the Singleton pattern I mentioned in a previous tutorial. The instance getter either returns the private _eventManager field if it is already defined, or it first assigns/initialises it and then returns it. This is a way to have a unique version of an object that is initialised just once and then accessed as many times as necessary.
Note: this pattern is like many others brilliantly explained by Bob Nystrom in his “Programming Patterns” book — I really encourage you to take a look if you’re interested in code design and architecture, especially in the field of video games (but not only!).
Just adapting Unity’s training session gives us the following script:





