Unity Singleton and static variables for Beginners

Unity Singleton or Singleton in general is a globally accessible class with all its objects referring to a single instance at any given time. A Singleton can have multiple objects but any reference to the class at a given point from different scripts will be to one single instance.

Confusing? Let’s try to understand it in detail.

When an object of a class is created, a memory is allocated to store its properties. In case of a Singleton, no matter how many objects are created they all point to the same memory location or otherwise termed as Singleton instance.

Unity singleton block diagram
Singleton Class vs Regular Class

In this tutorial, we will see how to create a Singleton class, using the static property and also how to implement their usage in the correct way.

If you looking for creating a static variable in Unity, then you can skip directly to the static variable part of this tutorial. But I suggest you read through the whole article to understand how the Singleton pattern works.

What is Singleton Pattern?

The singleton pattern is a design concept used in programming to ensure there is only one instance of a particular object.

Imagine you have a cookie jar in your kitchen. With the singleton pattern, you make sure there is only one cookie jar in the entire house. No matter how many people are in the house or how many times they want a cookie, they will always go to the same cookie jar.

This pattern is helpful when you want to avoid unnecessary duplication of objects and ensure that everyone is accessing the same instance of an object. It’s like having a single, shared resource that everyone uses, guaranteeing consistency and avoiding confusion.

So, it’s a general practice, to create only one object for a Singleton class and check if any duplicates exist and destroy them. We will see how to do this in the later section of this tutorial.

How to create a Singleton in Unity?

You can make a class as a Singleton by declaring a public static singleton object of the class. With this object you can access any variable or method inside the class using the class name without needing to reference it first.

Let’s see some example

public class example : MonoBehaviour 
{
    public static example my_object;

    float my_player_health=100;
}

In the above code the example class is a singleton and has a static object called my_object. Now if I want to access the variable my_player_health from other scripts I can do it like this

public class test: MonoBehaviour
{
   
   void Start()
   {
      float player_health=example.my_object.my_player_health;
   }

}

You can read and write the properties from any class. But if you want to change the read and write permission of a Singleton class, you can do that when declaring the static object.

Here is an example of how you can make the Singleton Read-only.

public class example : MonoBehaviour 
{
    public static example my_object { get; private set; } ;

    float my_player_health=100;
}

How to Find and delete the duplicate instances of a Unity Singleton?

As we discussed in the introduction, a class, Singleton or not, can have more than one object but all of them refer to the same Singleton instance. This adds to more confusing and makes it difficult to implement a singleton.

To avoid this confusing, we can just add a code to check, if the instance created is the only active instance of the class. If not, the instance can self-destroy itself. This way, even if multiple Singleton instances are created only one remains in the end.

In general C# code, you can use a constructor of the class to do this but Unity does allow constructor if you inherit from MonoBehaviour. So, we can add the code to the Awake function.

public class example : MonoBehaviour 
{
    public static example my_object { get; private set; } ;

    float my_player_health=100;

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

Where to use Singletons in Unity?

1.To avoid Multiple instances of the same class

Singletons are generally used for data that needs to be accessed from different scripts. For example, the player data. Player data is accessed by multiple scripts for different purposes.

The UI accesses the data to display health bar, the scene manager requires it to load scenes, the audio manager requires it to play audio and so on.

All these scripts can create an instance for the player class and access the data but that will be a waste of resource and memory. Instead of that you can create a single Singleton class for the player which holds all data like Player health, position, ammo etc.

All the other scripts can use the player data without creating an instance for the class.

2. To improve performance

Many coders in Unity have a habit to use GameObject.Find very extensively. It is a very performance hungry class and you can avoid it using a Singleton.

For example, if you need to change the color of a Game object from another script then you need to find the game object and then change the color.

This can be done in a simple manner using Singleton without finding the game object.

The below code is changing the color of the target renderer based on the game score.

using UnityEngine;

public class ScoreManager : MonoBehaviour
{
    public static ScoreManager Instance { get; private set; }

    private int score;

    [SerializeField] private Renderer targetRenderer;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }

    public void UpdateScore(int points)
    {
        score += points;
        Debug.Log("Score updated: " + score);

        // Change color of the GameObject based on the score
        if (score >= 100)
        {
            // Change color to green
            ChangeColor(Color.green);
        }
        else if (score >= 50)
        {
            // Change color to yellow
            ChangeColor(Color.yellow);
        }
        else
        {
            // Change color to red
            ChangeColor(Color.red);
        }
    }

    public void ChangeColor(Color color)
    {
        // Change the color of the target Renderer component
        targetRenderer.material.color = color;
    }
}

The ChangeColor() function can be called from a different script using the static object as shown in the example below.

using UnityEngine;

public class ColorChanger : MonoBehaviour
{
    private void Start()
    {
        // Example usage: Change the color to blue when the game starts
        ScoreManager.Instance.ChangeColor(Color.blue);
    }
}

3. To create a game manager

For example, let’s consider a Game Manager that handles the overall game state, such as score tracking, level management, and player progression. Here is an example game manager script

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;  

    // Variables for game state
    private int score;
    private int currentLevel;
    private int playerLevel;

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

    // Example game management method for score tracking
    public void UpdateScore(int points)
    {
        score += points;
        Debug.Log("Score updated: " + score);
    }

    // Example game management method for level management
    public void LoadLevel(int levelIndex)
    {
        currentLevel = levelIndex;
        Debug.Log("Loading level: " + currentLevel);
    }

    // Example game management method for player progression
    public void IncreasePlayerLevel()
    {
        playerLevel++;
        Debug.Log("Player level increased: " + playerLevel);
    }

    // Example game management method to reset game state
    public void ResetGameState()
    {
        score = 0;
        currentLevel = 0;
        playerLevel = 0;
        Debug.Log("Game state reset.");
    }
}

In this code, the GameManager class is a MonoBehaviour responsible for managing the overall game state. The instance variable is a static reference to the single instance of the GameManager.

The Awake function is used to handle the creation and destruction of the GameManager instance. If there is no existing instance, the current GameManager object (this) is assigned to the instance variable and marked as DontDestroyOnLoad to persist it between scene changes. If an instance already exists, the newly created GameManager object is destroyed to ensure only one instance exists.

The GameManager includes example game management methods (UpdateScore, LoadLevel, IncreasePlayerLevel) to demonstrate the handling of score tracking, level management, and player progression. Additionally, there’s an example ResetGameState method to reset the game state.

Other scripts or components can access the GameManager instance through GameManager.Instance and utilize its methods and variables for game management tasks, such as updating the score, loading levels, increasing the player’s level, or resetting the game state.

Through the use of the singleton pattern, we can access the GameManager instance from anywhere within the game by calling GameManager.Instance. This provides a convenient way to access and utilize the functionalities of the GameManager without needing to manually pass references between different components.

How to Avoid the Singleton from getting destroyed on Scene load?

Even though a Singleton is very handy, it’s important to note that it gets destroyed on scene load. So, if you set your player health in the intro scene and switch to the game scene, then all the data is gone.

Unity provides a way to avoid this by not destroying the Singleton when the scene changes.

You need to add just a single line to code for this. It’s called DontdestroyOnLoad.

public class example : MonoBehaviour 
{
    public static example my_object { get; private set; } ;

    float my_player_health=100;

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

Static variable and methods in Unity

Singleton are actually static instances of a class. Similar to a class you can also create a static variable and a static method. A static variable or method can be accessed from anywhere or any other script using the class name.

You don’t need an object reference to access the static properties.

To declare a static variable or method, you need to use the keyword static. It’s very similar to how we declared the static object of a class.

Here are the examples

Static Variable

public static int level_count;

Static Method

public static void my_method()
{

}

Let’s say they are a part of the class named example. Now to access the data. you can simply use the class name without needing to reference it.

int my_value=example.level_count
example.my_method()

Singleton vs Static variable usage in Unity

Both are very similar when it comes to how the data is stored. Depending on your requirement, you can decide if you have to use a Singleton class or a static variable.

Let’s consider an example for better understanding.

If you need only the player health variable in all scripts, then there is no point in making a Singleton player class you can only have a static player health variable.

If you need all the methods and variables inside the player class, then it’s better to create a singleton rather than creating multiple static properties.

Hope this clears everything about Singletons in Unity. If you have any questions feel free to leave them in the comment box below.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from VionixStudio

Subscribe now to keep reading and get access to the full archive.

Continue reading