My Singleton Solution

UPDATE!

Lesson #84 in the Unity 2D course (toward the very end of Block Breaker) now addresses the problem and provides Sam’s solution.

This thread is no longer necessary.

THE PROBLEM

As of the time I write this, there is a problem in the singleton pattern being taught. The singleton code is put into the Awake() method. The idea is that this code will be run as soon as the singleton object is created, check to see how many such items there are, and if there is more than one, the new item will destroy itself.

This has created some problems since the “Destroy()” method has a delay and will not actually destroy the object until after the Update() method is complete. That means during the Awake(), Start(), and Update() methods of the first frame in the scene, you may have duplicates in your hierarchy, which can cause havoc with things like FindObjectsOfType. Some people in the courses are having problems with this now. Since FindObjectOfType returns the first instance it finds, it’s important that there’s only one.

The current singleton code works like this:

 private void Awake()
    {
        int gameStatusCount = FindObjectsOfType<GameSession>().Length;
        if (gameStatusCount > 1)
        {
            Destroy(gameObject);
        }
        else
        {
            DontDestroyOnLoad(gameObject);
        }
}

MY PROPOSED SOLUTION

Originally, when Ben taught the singleton pattern, he taught it with this code, which seemed very confusing at the time (which is why I think they changed it to something simpler):

public class GameSession : MonoBehaviour {
	public static GameSession instance = null;
	
	void Awake () {
		if (instance != null && instance != this) {
			Destroy (gameObject);
			print ("Duplicate GameSession self-destructing!");
		} else {
			instance = this;
			GameObject.DontDestroyOnLoad(gameObject);
		}
}

It’s weird to have an object with a reference to itself, but it’s not that hard to grasp. It’s like a person talking about themselves in the third person. Anthony does that sometimes.

When the first instance of this code is run, it assigns itself to the name “instance”. When the second instance of the code is run, it sees that “instance” already has a reference so it doesn’t bother. Neither will the third, the fourth, etc. As long as “instance” already refers to something, nothing else is going to assign itself to “instance”.

This is helpful because it means that the variable “instance” always refers to the same instance (unless something happens to that instance like it gets destroyed or something). Even if we somehow grab the wrong instance when finding objects, we can use its “instance” variable to find the proper one.

This seems like better code to use, but it’s not perfect. I’ve heard it doesn’t work very well once you start using advanced features like threading and such. It also requires a little bit of self-discipline to use properly because we have to remember to use the “.instance” reference after finding the object so that you are always referencing the same “singleton”.

I still don’t think this is actually a singleton since it still allows more than one object to exist for a brief period, but at least if you use the “.instance” reference, then you are never accessing the wrong one.

So, if GameSession has a variable like int playerLives = 3; and a public function like GetPlayerLives() to return that variable, for example, you might access it this way from a different script:

gameSession = FindObjectOfType<GameSession>();
playerLives = gameSession.instance.GetPlayerLives();

“.instance” is a reference that exists on all of your GameSession script and is always a reference to the same gameSession object, no matter which of them it was referenced from. So this will work.

The problem now is that if your FindObjectOfType found the wrong duplicate class, then that object will be destroyed soon. This means you are trying to access a reference variable on a class that no longer exists? That means critical errors. That means really bad things.

We have to make sure that once you find the right instance, the gameSession always points back to the proper instance and never again needs to access the first gameSession you found.

This just requires one additional step:

gameSession = FindObjectOfType<GameSession>();
gameSession = gameSession.instance;
playerLives = gameSession.GetPlayerLives();

The first line gets us a gameSession. Any one. We don’t care if its the right one or not, since they all have a reference to the right one anyway. The second line redefines gameSession to refer to the proper instance instead of the one we found. After that, gameSession can be used normally in the script. We don’t even really need the “.instance” anymore.

UPDATED AND IMPROVED

Rob and cornucanis brought to my attention that adding a static property to my code would make the code easier and safer to use. A property looks a lot like a variable except it doesn’t store data. Instead, it’s used to access another variable. This allows you to access a variable using a different name or access level. In this case, we’re making a property that has public read-only access while the variable itself is completely private. By convention, properties have their first letter capitalized.

The property I’ll be using is called “Singleton”. When accessed, it returns the “instance” variable from the same class. Because its a “static” property, it belongs to the class itself rather than any instance so we don’t have to worry about finding objects.

Properties are declared like variables except they are followed by accessors that immediately tell you what the property does. There are a couple different ways of writing these and most people seem to prefer the shortest way possible. I have kind of a weird way of writing out my accessors because I’m still learning to use them and I want to be absolutely clear and see at a glance what the property is doing.

Let’s get crackin’.

public class GameSession : MonoBehaviour {

	private static GameSession instance = null;
        static GameSession Singleton {get{return instance;}}
	
	void Awake () {
		if (instance != null && instance != this) {
			Destroy (gameObject);
			print ("Duplicate GameSession self-destructing!");
		} else {
			instance = this;
			 GameObject.DontDestroyOnLoad(gameObject);
		}
}

Since we are using static variables and properties, there’s no need to find a gameSession object as I was trying to do above. These static values will also be shared by the overall GameSession class, which we can access from anywhere in our code. When we access GameSession, we won’t be able to see “instance” because it is a private variable but we will be able to see “Singleton”. Since it is also private and only has a “get” accessor (and no “set” accessor), we can get information from Singleton from outside the class but we can’t change it. Accessing “Singleton” returns the reference stored in “instance”.

Again, just to be clear: “instance” is a variable, which holds information. “Singleton” is a property, which provides a means of accessing “instance” but holds no information itself.

So, if GameSession has a variable like int playerLives = 3; and a public function like GetPlayerLives() to return that variable, for example, you might access it this way from a different script:

GameSession.Singleton.GetPlayerLives();

Much easier. No finding objects or anything like that.

STILL NOT A SINGLETON, BUT GOOD ENOUGH

Again, just to be absolutely clear: This isn’t really a singleton. It’s close enough for our purposes but I want you to understand the difference just in case you talk with more experienced programmers or read stuff in forums or something.

A true singleton needs to be procedurally generated and requires some active code that decides whether or not to instantiate a singleton based on whether one already exists or not.

The singleton-like scripts we are making are self-contained scripts that come into play and then decide for themselves whether they should stay in play.

CONCLUSION

I think this is the best solution for a beginner until we learn some more advanced coding techniques. I’ve looked online for singletons, but most of them are for trying to handle “perfect singletons” that cover lots of edge cases, and include things like threading, locking, constructors, and a bunch of other stuff.

Right now, I think this is the best solution that is easy for beginners to understand and implement. (Maybe not absolute beginners, but certainly once you’ve made some progress through the course.)

The problem with the Singleton pattern is that we need it before we really have the foundational knowledge to understand it. The second problem is that there really seems to be different ways to handle it based on what kind of edge cases you want to protect against. This proposed solution is to handle a case where we frequently need to find our singleton objects at the start of each scene.

If you have another solution that works for you, feel free to share it. If you see anything wrong with something in this post, feel free to warn your brethren.


Sam’s Proposed Solution

Sam has recently suggested a simple fix to Rick’s code that may solve the issue we are having. It’s so simple that I’m a little embarrassed. At the time that I write this, this solution is still being tested by the gamedev.tv team and not yet officially approved - but it looks okay to me. I won’t be using it since I’ve grown accustomed to the advantages of the solution proposed above, but I admire the simplicity of this fix, which just adds one line of code:

int numberGameSessions = FindObjectsOfType<GameSession>().Length;
 
    if (numberGameSessions > 1)
    {
        gameObject.SetActive(false); //<--- this
        Destroy(gameObject);
    }
    else
    {
        DontDestroyOnLoad(gameObject);
    }

By also setting the gameObject to inactive when you tag it for destruction, you prevent any other scripts from finding it or interacting with it. So it doesn’t matter if there’s two, because one is inactive and essentially invisible.

7 Likes

Hey Anthony,

You could also use a public, read-only, property and keep the instance variable private, for example;

public class GameSession : MonoBehaviour
{
    private static GameSession _instance = null;

    public static GameSession Instance
    {
        get { return _instance; }
    }

    private void Awake()
    {
        if(_instance != null && _instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            _instance = this;
            DontDestroyOnLoad(gameObject);
        }
    }
}

This would restrict the ability for anyone to overwrite the otherwise expose public variable. A side benefit is that you can keep the variable name lowercased, and use the property with a capitalised first letter (oh so important for my OCD!).

So, if GameSession has a variable like int playerLives = 3; and a public function like GetPlayerLives() to return that variable, for example, you might access it this way from a different script:

gameSession = FindObjectOfType<GameSession>();
playerLives = gameSession.instance.GetPlayerLives();

As the variable in your example, or the property in mine, is static, you don’t really need to use FindObjectOfType, you could just access it via the class;

playerLives = GameSession.Instance.GetPlayerLives();

The above would remove the chance of FindObjectOfType returning the wrong object from the scene.

3 Likes

At first I was confused about what you were suggesting until I went back and compared it to my code above. You’re totally right! Leaving “instance” as a public variable gives everything access to modify it and that’s not a good idea.

1 Like

While I love to get replies from them, I normally abhor the practice of pinging instructors or admins just to call attention to a post. But I will make an exception in this case and attempt to ping @Rick_Davidson.

This subject may be of interest to him at this time since a recent post by the student instructor in the Q&A has indicated that he may be in the process of investigating the singleton issues we’ve been seeing.

edit: …aaaand I just got an accolade for my ‘first mention’. :stuck_out_tongue:

1 Like

aaaand I just got an accolade for my ‘first mention’. :stuck_out_tongue:

:+1:

Wear you badge with honour! :slight_smile:

Hi Guys,

I handed this back to the team via @Nina as it appears in the 3D course and RPG as well.
I am not currently certain on the outcome or feedback as yet on this.

If i get anything back before Rick or another member of the team replies i’ll pop a note here but as of yet i dont have an answer either way.

I also went with Anthony’s solution as well on this.

Just a small issue with your use of this singleton implementation, specifically this part:

gameSession = FindObjectOfType<GameSession>();
gameSession = gameSession.instance;
playerLives = gameSession.GetPlayerLives();

This is not how you access static properties. Static properties are, by definition, available without the need to reference a specific instance of the class. If you wanted to call the static property mousePosition of the Input class, you wouldn’t need to use FindObjectOfType<Input>() because you can simply use Input.mousePosition. Similarly, due to the use of a static property your 3 lines I copied above can be condensed to

playerLives = GameSession.instance.GetPlayerLives();

This is the true power of using a static property for your singleton. You never have to actually find the object in the scene, you can easily call it from any other class simply by using the singleton class’ name.

1 Like

Nina just posted an excellent solution in the Q&A. It uses Rick’s original code, but adds just one line.

    int numberGameSessions = FindObjectsOfType<GameSession>().Length;
 
    if (numberGameSessions > 1)
    {
        gameObject.SetActive(false); //<--- this
        Destroy(gameObject);
    }
    else
    {
        DontDestroyOnLoad(gameObject);
    }

By also setting the gameObject to inactive when you tag it for destruction, you prevent any other scripts from finding it or interacting with it. It bypasses the issue altogether.

Thanks for your post. This helped me address an issue I had.

Lesson #84 in the Unity 2D course (toward the very end of Block Breaker) now addresses the problem and Sam’s solution.

This thread is no longer necessary.

1 Like

Thank you so much! Thanks for pointing out lecture 84. I’m at lecture 70 and I cannot get my score to update. Thanks for saving me so much time!

1 Like

The thread might not be “necessary” but I learned a great deal from it, so thank you!

4 Likes

In another thread it was noted that using DestroyImmediate(gameObject) also solves this problem. I tried it and it did work in my code, so that is another option.

I have been told never to use DestroyImmediate as it can have nasty side effects. Even Unity’s docs recommend against using it. It’s like being restricted from doing something because there’s built-in safety protocols to stop what you are trying to do so you “fix it” by bypassing the safety protocols.

1 Like

Good to know!

Privacy & Terms