I hate singletons. Singletons are by many considered an anti-pattern, and I am a proud to be among them. However, that doesn't take away from the fact that we sometimes need to interact with static classes through GameObjects. Let me show you how to do it safe.
I think a large part of the problem with singletons stems from the fact that most people introduce them early in the process. When you introduce singletons as your solution, you are setting yourself up for a lot of issues through coupling and violation of the single-responsibility principle. Instead, think of singletons as state setters that provide a designer-friendly way to interact with static classes if all else fails.
We are going to write a singleton that sets the state of the Cursor. But before we make a singleton, let's just make a state setter.
Adding this to your player will set the Cursor state on the start of your game. Adding it to your pause screen will set it when you pause. It becomes trivial to chain state setters via components.
The loose coupling here is by design. We want our state setter to set state once, but do nothing else. If something else wants to manipulate the state of Cursor, it should be free to do so.
However, a problem arises when we go back from our pause menu to our game:
After we unpause, our Cursor is still visible, and our Cursor state for the player is lost.
To address this, we'll use the singleton pattern. It will be easier to explain if I show you the code first:
The last enabled instance will be the active one, like we're adding our instances onto a stack. When we disable, we will reset to the last active instance in the stack.
If we apply this pattern to our CursorInstance, we effectively fix our Cursor resetting when we unpause.
Unlike most singletons, we expect ours to change quite a lot over the duration of our game. This allows our designers to change state often and in creative ways.
Our pause screen resets the Cursor, but now we also want it to stop Time. Adding instances is incredibly easy:
With our new TimeScaleInstance, we can easily stop Time whenever we pause.
This leaves you safe to program in static classes without the use of anti-patterns that will ruin your codebase and set you up for headaches down the line. As you can see, there is a safe way in Unity to use singletons, as long as you don't use singletons to hold state, but as instances that transfer state instead!
Did you like this post? Tell us
Leave a comment
Log in with your itch.io account to leave a comment.