Don'tDestroyOnLoad() - Nulls out references

Hi Everyone,
Pretty new to Unity. I’m trying to create a persistent singleton GameController. It’s an empty game object, in the scene when the game starts, and has a single script. The script has a reference to a player prefab, and an enemy manager prefab. These are set in the inspector and used to start spawning enemies, track whether the player is alive, and reset the game.

I have used DontDestroyOnLoad() to keep the game manager in memory as I intend to use it to track score, lives, etc. Everything works fine on first load, but after resetting the game, my player and enemyManager references seem to be getting nulled out even though I re-instantiate and re-assign them. The really weird thing is that they both contain references to their respective game objects in Awake(), after initialization, but in Update() they are null. I don’t want to do DontDestroyOnLoad() on the player and enemy manager because I want to reset the game. How can I re-intialize my references? Thanks for any responses!

using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour 
{
    public GameObject playerPrefab;
    public GameObject enemyManagerPrefab;

    private GameObject player;
    private GameObject enemyManager;

    private EnemyManagerScript enemyManagerScript;

    private static GameController _instance;

    public static GameController instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = GameObject.FindObjectOfType<GameController>();

                //Tell unity not to destroy this object when loading a new scene!
                DontDestroyOnLoad(_instance.gameObject);
            }

            return _instance;
        }
    }

    void Awake()
    {
        if (_instance == null)
        {
            //If I am the first instance, make me the Singleton
            _instance = this;
            DontDestroyOnLoad(this);
        }
        else
        {
            //If a Singleton already exists and you find
            //another reference in scene, destroy it!
            if (this != _instance)
                Destroy(this.gameObject);
        }

        Init();
    }

    void Init()
    {     
        player = Instantiate(playerPrefab);
        player.name = "Player";
        enemyManager = Instantiate(enemyManagerPrefab);
        enemyManager.name = "Enemy Manager";
        enemyManagerScript = enemyManager.GetComponent<EnemyManagerScript>();
        enemyManagerScript.SpawnEnemies();
    }

    void Update ()
    {
        if (player != null)
        {
            if (player.GetComponent<PlayerState>().IsAlive == false)
            {
                ResetGame();
            }   
        }  
    }

    void ResetGame()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

Awake is only called once in the lifetime of the GameObject. When you do DontDestroyOnLoad on your GameController, it won’t call it’s Awake function after you load a level - it has already awake’d.

Your characters are showing up in new scenes because the GameController you have placed there are calling their Init. When you do this:

else {
    //If a Singleton already exists and you find
    //another reference in scene, destroy it!
    if (this != _instance)
        Destroy(this.gameObject);
}

Init();

The Destroy call destroys the GameObject, but the method still finishes. So it’s not your singleton that’s spawning the Player and EnemyManager, but the object you’re destroying.

The best fix is to use the OnLevelWasLoaded callback, and call Init again from there:

void OnLevelWasLoaded(int level) {
    Init();
}

And then only call Init if this GameManager is the first one:

void Awake() {
    if (_instance == null) {
        //If I am the first instance, make me the Singleton
        _instance = this;
        DontDestroyOnLoad(this);
        Init();
    }
    else {
        //If a Singleton already exists and you find
        //another reference in scene, destroy it!
        if (this != _instance)
            Destroy(this.gameObject);
    }
}

That should fix the problem.