You have probably heard that you should use design patterns when developing games or any kind of software. However, some of us are stubborn enough to think that we do not need them. Well, if you think that way, you are wrong. I used to think that if I write organized code I would not need design patterns. One day, I reached a point in a project where I realized I was wasting development time and effort trying to find errors that could be avoided by using design patterns. Being organized was not enough. Let me tell you how I started using the Singleton pattern.
If you are not familiar with design patterns, it is ok, you do not need to know about them to laugh with this story. First, let me tell you that, Singleton, the simplest design pattern, consists in the creation of a class that can be instantiated only once.
Now that we know what Singleton is, let’s go back to my story. I used to think that having a script that was not destroyed on load could replace a Singleton. Therefore, in my main scripts, the ones that control the logic of my game, data, sound, and Input/Output I had the following line of code:
DontDestroyOnLoad(gameObject);
This way, they would be persistent through the whole game. The first problem that I found with this solution was that it made it really annoying every time I wanted to access these scripts, which was very often. I remember that I had to find the object and then get the script component that I wanted (very inefficient implementation). Another solution that I used was to have references to the main scripts in some of the other scripts that interacted with them more frequently. Yes, I know. This was an extremely bad replacement for a Singleton. One day, I was looking at my code and I saw the high number of references that I had to those main scripts. The code did not look organized and was not efficient. I could not keep adding changes to my project because the base of it was bad. It would cause more problems in the future to deal with my solution than to refactor my code. Well, I was wrong, I look at myself in the mirror, accepted my mistake and decided to start using Singleton from that moment on. I refactored all the scripts that needed to be singleton and persistent to add the following code:
public class SceneManager: MonoBehaviour
{
void Awake()
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
public static SceneManager Instance{ get; private set; }
}
For instance, this is how I access my SceneManager class after implementing the Singleton pattern in it:
SceneManager.Instance
I felt great because I did not have to search for my class anymore, nor add extra references in other scripts. In addition, I was using design patterns in my project like good programmers do. Well, not quite. Unfortunately for me, the previous implementation was incomplete.
One day, yes, another day, I was testing a scene in my project. To make testing faster, I added a prefab of a game object that contained the main scripts, which loaded all the data needed in the game. As you can imagine, I forgot to remove that game object after testing. Which I discover after 1 hour of debugging. I mentioned my problem to a friend and he told me that my Singleton implementation should have handled that problem in the Awake method. Singleton checks whether the class was instantiated or not to destroy the second game object that was trying to create the new instance. I was like: “Ok, I do not check any of that.” My implementation was wrong, again. However, this last time, I checked on the internet and asked my friend to give a look at my code before I keep making changes. I finally had a good implementation of a Singleton.
public class SceneManager: MonoBehaviour
{
void Awake()
{
if(Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
public static SceneManager Instance{ get; private set; }
}
Now, I can access my scripts easily and ensure that only one instance of a class will be created. I hope you have learned with this story that you should not reinvent the wheel. If there is a solution already, and it is good, use it. Be critical with your code and if you can tell someone else to review it. Both of you can learn from a code review. If you had problems in your code, just like I had, do not think you are a bad programmer. Making mistakes is good, we grow when we learn from them. Remember that programming is a discipline that is improved through iterations.


