I’ve abandoned more Unity game projects than I can count, and it’s only recently that I’ve started to develop in a way that feels sustainable. Something I’ve always struggled with is how to organise my code — designing a game that’s fun to play is one thing, but designing systems that are easy to work with and don’t become unwieldy and bogged down after a few months is another thing entirely.
Turns out it only took a year of working in software professionally to show me that there are some really easy ways to fix these project-destroying patterns, and you can start using them immediately.
One design pattern I’ve been incredibly thankful for lately is the Event Hub Singleton. This is a trick I picked up off a colleague, and which I’d never have stumbled across on my own, no matter how much googling I did. If you find yourself adding dozens of public fields to your scripts to hold references to other GameObjects, bloating your code and giving you a greasy feeling whenever you have to edit it in the inspector, then this is for you.
If you haven’t come across the concept of a ‘singleton’ before, don’t worry: it’s pretty simple. A singleton is just a class that only allows one instance of itself to exist.
People often do these in Unity by having a single gameobject called something like GameController, with a GameController script containing loads of public static functions. I’ve seen more scripts than I can count where some poor doomed developer has written something like:
But what if you could just write this?
You can make your code better, more modular and easier to work with by having singletons in your scripts folder that aren’t components, and can’t be attached to GameObjects. It can feel a bit weird if you learned C# alongside Unity, but there’s no harm in it, and it can lead to healthier, more organised projects.
Simply add a new script, and then change this:
Simple, right? Now you can call ScoreManager.Instance from anywhere in your code to get access to it as if it was a static class, but without any of the restrictions of a static class.
You can add public and private functions to it as normal, and none of them need to be static since the class is instanced the first time you try to use it.
That’s an easy tip you can start using now to make your projects easier to manage — but if you want to go a bit further you can now make Event Hubs!
Event Hubs as Singletons
Now we’re riding the heady wave of single living, it’s time to do what every singleton eventually does, and decouple ourselves from the concept of time. No, I’m not talking about losing four weekends in a row to a bulk-ordered crate of cheap continental lager, I’m talking about event hubs!
I’m not sure what the real word for this concept is because I’m pretty sure the guy who taught me about them stole the name from some obscure Microsoft Azure service, but an Event Hub is basically a way of making C# events really easy to keep track of and understand.
I never bothered much with events in game programming because I was never really sure where to put them or how to track them, and because all my GameObjects had references to each other anyway I figured I might as well just have them call each others’ functions to do what I needed. This always ended up as the organisational equivalent of a beanie knitted out of spaghetti, but there is a better way.
Just create a singleton, then create an event in that singleton following this pattern:
public delegate void GoalScored(Player scorer);
public event GoalScored OnGoalScored;
public void RaiseOnGoalScored(Player scorer)
if (OnGoalScored == null)
Now because these events exist in a singleton class, they can be accessed by any object in your game. Because they have that null check, they’re not raised unless there’s at least one object subscribed to them (OnGoalScored is null if the event has no subscribers).
Now, for example, say you have a Football object that detects whether it’s been kicked into the goal, and tracks whoever the last Player to touch it was. Your Football can raise the GoalScored event and pass in that player, and your ScoreManager singleton can subscribe to that event.
Then your ScoreManager might have a bit of code that looks like this:
// Subscribe to the event by giving a function it can call
FootballEventHub.Instance.OnGoalScored += UpdateScore;
}// You must pass in the event's parameters
void UpdateScore(Player scorer)
// Don't forget to unsubscribe when you don't need it anymore!
FootballEventHub.Instance.OnGoalScored -= UpdateScore;
But the best bit is, because it’s an event, you can subscribe to the same event in multiple places. Maybe you want the player who scores to play a celebration animation? Sure, you could just call scorer.Celebrate() in UpdateScore, but what if you want all the players on the team to do it?
Instead of traversing Team’s list of players and calling Celebrate on each one, cluttering up your code and risking ConcurrentModificationException bugs, you can just subscribe each Player to this event as well.
Plus, you can check to see if that player is the same player who scored and play different animations depending on whether they’re celebrating their own success or a teammate’s.
That’s all there is to it! Hopefully you’ll find this useful — I know it might seem basic but as a self-taught programmer I never would have learned to do this if someone hadn’t explained it to me. I’ve found it a particularly useful pattern when working with scripts that exist outside Unity and decoupled from the GameObject/Component system.
For example, my current project has a universe simulation running in the ‘backend’ and it can raise events that all sorts of monitors and audiovisual effect managers in the Unity ‘frontend’ — as well as simulation actors in the backend — can listen out for.
For example, traversing an asteroid field causes impacts that trigger screen shake and cause the lighting to flicker on and off. Plus, if I want to add more things that respond to the same event, like electrical systems breaking or props getting knocked over, than I don’t need to modify any of the existing code.
Organising a growing project can seem daunting, and these kind of measures can feel like overkill, but the individual steps are easier than they look and it’ll make your life a lot simpler in the long run!
Anyway, that’s all my event tips. Feel free to hit me up on Twitter if you have any questions (or just want to show off).