petitviolet blog

    Singleton MonoBehavior to data live through Scene transitions

    2023-06-15

    UnityC#

    This post instructs how to achieve Singleton MonoBehavior in Unity C# that stay living even after scene transitions. Singleton is a well-known design pattern in the industry for long time and it's useful for having data and states in-memory or limit an active instance only one at the same time.

    In Unity C#, MonoBehavior is usually used to have references to objects in a scene and holds states after every single activity by users. However, every active objects like MonoBehavior associating with a scene will get destroyed when the scene is gone, and it's not expected if a MonoBehavior keeps states that should be available after scene transition completed. So, make a MonoBehavior singleton would be a way to keep states before and after scene transitions.

    C# code snippet for Singleton MonoBehavior

    As an example, DataHolder is a MonoBehavior and holds a state Dictionary<string, int> See the below snippet.

    singletonmonobehavior.cs
    using System;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace MyApp
    {
        public class DataHolder : MonoBehaviour
        {
            // anything living in a scene associated by UnityEditor
            [SerializeField] MyScriptableObjectPerScene _myObjectPerScene; 
    
            private Dictionary<string, int> _states = new Dictionary<string, int>(); // state
            private static DataHolder _instance; // singleton instance
    
            void Start()
            {
                if (_instance != null)
                {
                    _instance._myObjectPerScene = _myObjectPerScene;
                    Destroy(gameObject);
                }
                else
                {
                    // toe avoid `DontDestroyOnLoad only works for root GameObjects or components on root GameObjects.`
                    transform.parent = null;
                    DontDestroyOnLoad(gameObject);
    
                    _instance = this;
                }
                // state initialization per scene
                _states = _myObjectPerScene.Merge(_states);
            }
        }
    }
    

    This DataHolder achieves:

    • singleton to avoid more than 2 instances get active
    • keep data as its name describes even after scene transition