losing reference to game manager when scene loads

I’ve got a singleton set up with an overarching Managers class that has references to each of my other managers classes.

I also have a state machine set up that handles changing scenes between the Main Menu, the Gameplay, and the Game Over scene. These are also the corresponding states.

I’m using DontDestroyOnLoad on the Managers class so all that stuff should stay put between scenes.

The problem I’m running into however is that when it switches from the MainMenu to the Gameplay state, it apparently loses the reference to the GameManager object.

The error I get pops when I try to hit the GameManager for the second time when the game tries to change from Gameplay state to the Gameover state. It says it has been deleted, but if I put a debug.Log in the GameManager class’s update function, it is still firing. I have tried to put a method in the Managers class that I could call to reassign it after the new level is loaded, but that doesn’t seem to work. I have also tried the instructions found on this page here: http://wiki.unity3d.com/index.php/Singleton
also with no luck.

I’ve pretty much tried everything I could think of, and asked on several other sites but nobody could figure it out. Hopefully somebody here can shed some light on what the problem is and how to fix it.

Below is all the code I think should be needed for this and also an image of the error I’m getting. Thanks everyone!

public class Managers : MonoBehaviour 
{
public static Managers instance = null;

private static GameManager _gameManager;
public static GameManager Game 
{
    get{ return _gameManager; }
}

private static UIManager _uiManager;
public static UIManager UI 
{
    get{ return _uiManager; }
}

private static LevelManager _sceneManager;
public static LevelManager Level 
{
    get{ return _sceneManager; }
}

private static BoardManager _boardManager;
public static BoardManager Board 
{
    get{ return _boardManager; }
}

private static PickUpManager _pickUpManager;
public static PickUpManager PickUp 
{
    get{ return _pickUpManager; }
}

private static SoundManager _soundManager;
public static SoundManager Sound 
{
    get { return _soundManager; }
}


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

    DontDestroyOnLoad(gameObject);

    _gameManager = GetComponent<GameManager>();
    _uiManager = GetComponent<UIManager>();
    _sceneManager = GetComponent<LevelManager>();
    _boardManager = GetComponent<BoardManager>();
    _pickUpManager = GetComponent<PickUpManager>();
    _soundManager = GetComponent<SoundManager>();
}

void Update ()
{
    if (Managers.Game == null) //this if statement is here simply to show me that Managers does not have a reference to this anymore
    {
        Debug.Log("This is null");
    }
}
}




public class GameManager : MonoBehaviour 
{
public static MonoBehaviour monoBehaviour;
public bool isGameActive;
private int level = 50;
private _StatesBase currentState;

// Use this for initialization
void Awake ()
{   
    isGameActive = false;
    InitGame();
    monoBehaviour = this;
}

public _StatesBase State 
{
    get { return currentState;}
}

void InitGame ()
{
    Managers.Board.SetupScene (level);
}

public void SetState (System.Type newStateType)
{
    if (currentState != null) 
    {
        currentState.OnDeactivate ();
    }

    currentState = GetComponentInChildren (newStateType) as _StatesBase;
    if (currentState != null)
    {
        currentState.OnActivate();
    }
}

void Update ()
{
    Debug.Log("THIS IS A GAME MANAGER!!!"); //Just to check that it's still 
here. It is still showing even when Managers class reference is null.
    if (currentState != null) 
    {
        currentState.OnUpdate();
    }
}

void Start ()
{
    SetState(typeof(MainMenuState));
}
}


public class GamePlayState : _StatesBase 
{
public override void OnActivate ()
{
    Debug.Log("GamePlay OnActivate");
    Managers.Level.LoadLevel("Level_01");
    Managers.Game.isGameActive = true;

}

public override void OnDeactivate ()
{
    Debug.Log("GamePlay OnDeactivate");
    Managers.Game.isGameActive = false;
}

public override void OnUpdate ()
{
    Debug.Log("GamePlay OnUpdate");
}
}


public class LevelManager : MonoBehaviour 
{
public void LoadLevel (string name)
{
    SceneManager.LoadSceneAsync(name);
    Brick.breakableCount = 0;
}

public void QuitGame ()
{
    Application.Quit();
}

}

127343-error.png

This may not be your only issue, but the thing that pops up first is how you are handling your Awake method. Destroy() doesn’t fire immediately and thus the code that follows still get’s executed even for objects that are about to go away. So the order currently goes:

  1. GoodManager Awake() sets the instance
  2. GoodManager fires GetComponent() to grab references
  3. You change scenes
  4. GoodManager doesn’t fire Awake() again since it already has
  5. BadManager is in the new scene and fires its Awake() method
  6. BadManager sees that it is not the GoodManager and Destroys itself
  7. Before that happens though, BadManager changes all your static references to its components
  8. BadManager goes away and you now have null references.

You can instead structure your code like:

void Awake ()
 {
     if (instance == null) 
     {
         instance = this;
     } else if (instance != this) 
     {
         Destroy(gameObject);
         return;
     }
 
     DontDestroyOnLoad(gameObject);
 
     _gameManager = GetComponent<GameManager>();
     _uiManager = GetComponent<UIManager>();
     _sceneManager = GetComponent<LevelManager>();
     _boardManager = GetComponent<BoardManager>();
     _pickUpManager = GetComponent<PickUpManager>();
     _soundManager = GetComponent<SoundManager>();
 }

That should help. Try that and let me know what the results are.