Singleton Pattern

Welcome to part 2 of the Design Patterns series.
This episode will be about the Singleton Pattern!

Singleton Pattern

Design pattern singleton pattern | Develop Paper

Singleton is a pattern that restricts an object to one single instance and has a global point to access it.

Ensure a class has one instance, and provide a global point of access to it.

Singleton is a very popular and commonly used design pattern. This is because it has all it’s charms in being easy accessible. But that’s also it’s danger.

Example

Game Manager
A typical example of a singleton usage in games are game managers. An access point to store data. Simple data such as score, data and sometimes time can all be managed by one singleton based manager.

Scrabble letter
When you build a scrabble game, you’ll have one bag full of letters. This bag can be seen as a Singleton. There’s only one bag and every player is allowed to access it when it’s their turn. It’s a great way to store your letters data.
(More info about this here: click here)

Intentions of using singleton pattern

  • Eliminating instantiating multiple objects
  • Globally accessible
  • Central point for data

Demo

Demo introduction

For this demo we continue further with previous episode Façade Pattern.
This means I used Unity 2019.4.10 for this demo.
Please check out previous demo for full set up.

We’ll use singleton to add a score and high score system to this project.
This is a very common use for games to create a singleton for so, let’s try it!

Code

Singleton

Singleton.cs

For this singleton we’ll use Unity’s recommended singleton class they describe here: https://wiki.unity3d.com/index.php/Singleton
This is an abstract class we use as a base class for all our singleton usages.
This means that each of the classes inherited from this singleton class will not be able to instantiated multiple times and will be accessed by a static instance property.

namespace Singleton.Code {
    /// <summary>
    /// Singleton class from https://wiki.unity3d.com/index.php/Singleton
    /// 
    /// Inherit from this base class to create a singleton.
    /// e.g. public class MyClassName : Singleton<MyClassName> {}
    /// </summary>
    public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour {
        // Check to see if we're about to be destroyed.
        private static bool m_ShuttingDown = false;
        private static object m_Lock = new object();
        private static T m_Instance;

        /// <summary>
        /// Access singleton instance through this propriety.
        /// </summary>
        public static T Instance {
            get {
                if (m_ShuttingDown) {
                    Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
                                     "' already destroyed. Returning null.");
                    return null;
                }

                lock (m_Lock) {
                    if (m_Instance == null) {
                        // Search for existing instance.
                        m_Instance = (T) FindObjectOfType(typeof(T));

                        // Create new instance if one doesn't already exist.
                        if (m_Instance == null) {
                            // Need to create a new GameObject to attach the singleton to.
                            var singletonObject = new GameObject();
                            m_Instance = singletonObject.AddComponent<T>();
                            singletonObject.name = typeof(T).ToString() + " (Singleton)";

                            // Make instance persistent.
                            DontDestroyOnLoad(singletonObject);
                        }
                    }

                    return m_Instance;
                }
            }
        }


        private void OnApplicationQuit() {
            m_ShuttingDown = true;
        }


        private void OnDestroy() {
            m_ShuttingDown = true;
        }
    }
}
GameManagerSingleton.cs

Now we have the main Singleton added to our project, we can inherit our game manager from it.

namespace Singleton.Code {
    // inherit from singleton to have global access
    public class GameManagerSingleton : Singleton<GameManagerSingleton> {
        // player preference key
        private const string HighScorePref = "HighScore";

        // score
        public int Score { get; private set; } = 0;

        // high score cached variable
        private int _highScore = 0;

        // high score getter which checks if current score should overwrite.
        public int HighScore {
            get {
                if (Score <= _highScore) {
                    return _highScore;
                }

                _highScore = Score;
                PlayerPrefs.SetInt(HighScorePref, HighScore);

                return _highScore;
            }
        }

        private void Start() {
            // get last saved high score from player preferences
            _highScore = PlayerPrefs.GetInt(HighScorePref);
        }

        // returns new score
        public int AddScore() {
            Score++;
            return Score;
        }

        // resets score to 0
        public void ResetScore() {
            Score = 0;
        }
    }
}

Project adjustment

GameFacade.cs

To make the scoring system work, we must adjust the game façade to call the game manager single ton score properties and update visuals.

namespace Singleton.Code {
    public class GameFacade : MonoBehaviour {
        // text prefixes
        private const string ScoreText = "Score: ";
        private const string HighScoreText = "HighScore: ";

        ...
        [SerializeField] private Text _scoreText;
        [SerializeField] private Text _highScoreText;

        // game started boolean to prevent updates on initial call
        private bool _gameStarted = false;
        ...

        private void Start() {
            // initializing objects
            ...

            // initialize texts
            _scoreText.text = ScoreText + GameManagerSingleton.Instance.Score;
            _highScoreText.gameObject.SetActive(false);

            ...
        }
      
        ...

        private void OnEnemySurvived() {
            _foodMenu.EnableButtons();
            
            // added check so score does not update while game hasn't been fully initialized.
            if (_gameStarted) {
                _scoreText.text = ScoreText + GameManagerSingleton.Instance.AddScore();
            }

            // to make sure score doesn't get updated on first call
            _gameStarted = true;
        }

        private void OnEnemyDied() {
            // enable reset button when enemy died
            _reset.gameObject.SetActive(true);

            // refresh highscore text
            _highScoreText.text = HighScoreText + GameManagerSingleton.Instance.HighScore;
            // enable highscore text
            _highScoreText.gameObject.SetActive(true);
        }

        private void Reset() {
            // remove listeners
            sorcerer.OnSurvived -= RandomTarget;
            sorcerer.OnDied -= OnEnemyDied;

            // reset current scene and score
            GameManagerSingleton.Instance.ResetScore();
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }
}

I removed most of the code to highlight all the singleton usages. To see the remaining code, please check: https://justinbieshaar.com/facade-pattern/#gamefacadecs

Now we’ve only added two new text fields and update the texts using game manager singleton score properties

Git

Find the repository here with full source code:
https://github.com/jscotty/DesignPatterns

Or download the unity package here:

Breakdown

I made this simplified UML diagram to break down what happens.
As you can see the façade requests the current score and high score from the game manager singleton. The game manager singleton will check it’s score and return it’s value.

All the façade cares about is the data the game manager singleton results. The game manager singleton will be the only one responsible of managing and storing it, rest everyone is allowed to know it.

I always see Singleton Patterns like T-Shirts with a message on it. The person wearing it is the singleton since there is only one possible instance of this person. He choose to wear a shirt with a message everyone is allowed to see (public t-shirt).
If you start to use Singletons with this idea behind, it can have great uses for your project!

Commonly the Façade pattern is also using the Singleton pattern because mostly one Façade is required. But in this demo that wasn’t necessary needed.

Resources

Derek Banas

Game programming patterns book

Game Programming Patterns – Book Review

This is a great book for game development design patterns. I highly recommend to buy it or read for free on their website. Read for free or buy here: https://gameprogrammingpatterns.com

Assets

For the demo below I used three free art packages!

Evil Wizard
Free Pixel Art Hill
Free Pixel Foods

Hope you enjoyed this episode!
Were you already familiar with the Singleton Pattern? It has a great use and can help a lot with speeding up your production.

Note: be aware that this pattern also get over used too much. Sometimes developers think their whole game can exist of singletons creating lot of security problems to your application. So be selective when to use it or not.

If any questions, feel free to message me on Instagram @justinbieshaar or in comments below!

Happy coding everyone! 👨‍💻

Greetings,
Justin Scott

Follow Justin Scott:

I love to learn and share. - 01001010 01010011 01000010

Latest posts from

Leave a Reply

Your email address will not be published. Required fields are marked *