Menu
CoddyTech

Keep Between Scenes

Part of the Building Real Games section of Coddy's Unity journey. Lesson 20 of 60.

Loading a scene destroys every object of the old one, but some things must last the whole game, such as the coins a player carries from level to level. DontDestroyOnLoad(gameObject) moves an object out of its scene into a scene of its own, called DontDestroyOnLoad in the Hierarchy at Play, which loads never touch. It works on a root object only: on a child, Unity logs a warning and keeps nothing. The kept object's children come along, but the objects it only points at do not: after the load, a field that pointed at an object of the old scene holds a destroyed object, which compares equal to null.

public class GameSession : MonoBehaviour
{
    public static GameSession Instance;
    public int coins;

    void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

This GameSession lives in the Menu scene. Play goes Menu, Level1, then back to the Menu, and the Menu builds all its objects again, a new GameSession included, while the kept one is still there. Without the check in Awake there would be two, and the newcomer would take over Instance with 0 coins. With it, the newcomer finds Instance already set, destroys itself and stops, and the session that came through the levels stays.

The return matters because Destroy waits until the end of the frame. Without it the rest of Awake still runs for the newcomer: Instance = this; would point every script at an object about to be destroyed.

challenge icon

Challenge

Easy

Keep one run clock going through every scene load.

  1. In Awake(), if Instance != null, call Destroy(gameObject); and return;. Otherwise set Instance and call DontDestroyOnLoad(gameObject);.
  2. A load destroys the old level's text, so in Update(), before the text line, when clockText == null, set clockText = GameObject.Find("ClockText").GetComponent<TMP_Text>();.

Press Play, go to Level2 and back: one clock keeps counting. Then Check.

Try it yourself

using UnityEngine;
using TMPro;

public class RunClock : MonoBehaviour
{
    public static RunClock Instance;
    public TMP_Text clockText;
    private float seconds;

    void Awake()
    {
        Instance = this;
    }

    void Update()
    {
        seconds += Time.deltaTime;
        clockText.text = "Time: " + seconds.ToString("0.0");
    }

    public void Split()
    {
        Debug.Log("Split: " + seconds.ToString("0.0"));
    }
}

All lessons in Building Real Games

Practice on your own: Unity playground