Everything You Need to Know About Singletons in Unity

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
It’s time to cover a topic that I’ve been avoiding for a long time. And that’s the Singleton pattern. But first, I’m gonna need some coffee. Did I say coffee? I totally meant a beer, and I’m gonna need it. Alright, let’s do this. The Singleton Pattern. The Singleton Pattern is a design pattern that describes a class that is both globally accessible and can only be instantiated once. A classic example is the audio manager because, generally speaking, it’s something you’ll need to access in a lot of scripts and that you’ll want to make sure only exists once in any given scene. That doesn’t sound too bad, right? So why have I been avoiding Singletons for so long? Well, if you’re listening carefully, you may have picked up on something that makes the Singleton Pattern different from other design patterns — that it has two technical requirements. One, a singleton must be restricted to a single instance and two, it must also be globally accessible. Now, that might not seem like a big deal at first. But together these two requirements offer a tempting upfront value that is vastly outweighed by the pain they can cause in the long run. Let’s explore why by taking a look at each requirement on it’s own. Imagine a simple project with a Player, Game Manager, and some classes to handle basic tasks, like displaying health on the UI. In this example, the Game Manager is responsible for ending the game when the player dies, so it has a reference to the Player class. But how does it get access to the Player in the scene? Now, there’s actually a few ways to answer that question, and I have a video that covers each one. But, for the sake of this video, just know that we can either give the Game Manager a reference to the Player by setting an exposed property from another script or the editor, or we can have the Game Manager retrieve a reference to the Player for itself using, you guessed it, a Singleton which is globally accessible. The choice seems obvious, right? Why would I bother constructing some fancy way to pass the Player around my code when I could just turn it into a Singleton and get access for free? What could possibly go wrong? Well, as it turns out, quite a bit — just not at first. The Singleton Pattern solves a very big unknown in Unity, which is how do you access other scripts? Or, another way to look at it is how do you fill your class dependencies? Our Game Manager class depends on having a reference to the Player, which is obvious because the Player class is part of its member variables. Now, the effect I’m about to show you would be more dramatic in a real world scenario where our Game Manager is a few hundred lines long, but if we remove this member variable and access the Player singleton instance directly, we effectively hide the fact that the Game Manager depends on having access to the Player, which can lead to all sorts of problems down the road. Because you may know what your code is doing the day you wrote it, but I promise you won’t remember when you try to refactor it a week later. Or worse, try to explain it to someone else who’s contributing to your project. Hiding your class’ dependencies just makes everyone's lives more difficult in the long run. Now, admittedly, the pain of this might not seem obvious at first. But when you consider that a Singleton can be accessed from anywhere, it isn’t hard to conceive that you might actually start referencing them more and more throughout your code — because, let’s be honest, it’s just so easy. And with all those hidden dependencies comes a layer of complexity that should be avoided as much as possible. But that isn’t the only issue. Here are two examples of our Player singleton being used in the previous project. We’ve got a health bar and some logic to save the game. Both access the player’s health, which is nice and consistent. But what happens if we need to change how health works — say we want to add a special type of Player that factors armor into its overall fortitude. Well, any change we make to our singleton will affect the entire game because the Player class is being referenced directly via the Singleton Instance variable. However, if we refactor these classes and make the Player class a dependency, we can fill that dependency with any class that derives from Player, such as a class called ArmoredPlayer that implements the previously described functionality. Again, these pain points are subtle but their effects snowball as your project grows. What seems easy to change here in these discrete examples is much harder to do in a real world scenario. So much so, that you may find yourself exploring the Ballmer Peak to make it through your day. Now, we’ve been talking about how using Singletons can be harmful to a project, but their implementation, specifically in Unity, can be harmful, as well. The other technical requirement of a Singleton is that it must be restricted to a single instance. To accomplish this restriction you’d normally hide your Singleton’s constructor by making it private and then lazily instantiating a single Instance from the getter. But this typically doesn’t work in Unity because most of your classes will probably derive from MonoBehaviour. And MonoBehaviours hide the constructor and allow anyone to instantiate them via Object dot Instantiate. So how do you restrict MonoBehaviours to a single instance? Well, you can do it but, unfortunately, it requires some finagling to get it to work. The concept is the same in that if the Singleton MonoBehavior doesn’t have a reference to an instance yet, it’ll go ahead and create one of its own. But, first it has to check the scene to confirm that one hasn’t already been created. That’s because there are a couple ways that yourself or another developer can circumvent the single instance restriction — by adding one or more instances directly into the scene from the editor, or by calling Object dot Instantiate, like I mentioned before. So, the getter will need to check the scene and grab the first instance it finds. Notice I said, “the first instance”. Because you could actually have multiple Singletons in your scene. So MonoBehaviour based Singletons must destroy themselves if another one exists when they’re created. Which adds a bit of magic that can lead to some unexpected behavior. For example, if your Singleton makes a call to DontDestoryOnLoad in order to persist through scene changes, there’s a chance that there’ll be an instance of that Singleton in the new scene. And, what can happen is that, depending on the order they’re arranged in the hierarchy, the wrong one could be deleted. So, it works but it isn’t the best solution. Now, where does that leave us? Am I saying to never use Singletons again? Well, let me put it this way. I and many other developers get by just fine without them. I could get into more detail about how using Singletons informs how you architect your entire project and creates bad habits that cause you to tightly couple your code which effectively destroys its flexibility in the long run. But instead, let me leave you with some criteria to follow the next time you want to use a Singleton. One: does having more than one instance of your potential Singleton fundamentally break your game? I mean, would your code literally throw an exception and crash if you had more than of them in a single scene? Two: does it absolutely need to be accessed by different parts of your code? And I’m not just talking about something like a player class that might get referenced in the UI and the game manager, but does your potential singleton need to be accessible by every nook and cranny of your code base? And finally, three: will your singleton control concurrent access to a shared resource? Think of a data manager that has the ability to open and close a save file, where simultaneous access to the file would actually throw an exception. If you keep those three criteria in mind, then you should have no trouble implementing Singletons that actually provide long term value to your project. Otherwise, I strongly suggest learning the techniques that you can use in Unity to safely pass data around your game code. And you can start with my video called “How to Access Variables From Another Script in Unity”. Pretty on those nose, right? Give that a watch and let me know what you think in the comments. Now, I know there are some pretty die hard Singleton users out there. So if you think I missed the mark, let me have it. Or if you agree with this video, then I’d love some positive feedback as well. Welp, as always, thanks for watching and I’ll catch you in the next video. Cheers.
Info
Channel: Infallible Code
Views: 86,525
Rating: undefined out of 5
Keywords: unity singleton, singletons unity, singletons in unity, singleton unity c#, singleton unity, unity singleton pattern, singleton pattern unity, singleton pattern unity c#, singleton pattern in unity, singleton in unity, unity singletons, singleton design pattern unity, unity singleton 2019, unity singleton 2020, unity, unity3d, unity 3d, singletons singleton design pattern, infalliblecode, infallible code, unity design patterns c#, unity3d singleton, singleton pattern
Id: mpM0C6quQjs
Channel Id: undefined
Length: 8min 37sec (517 seconds)
Published: Sun Feb 16 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.