Singleton GameState broken delegate?

Hi all,
I’ve been trying to create a Singleton GameState manager but keep running into the same problem.

I’m using a public delegate to handle events that are changing the GameState enums. I am running into an issue where if I inherit from MonoBehaviour DontDestroyOnLoad is nonfunctional due to my use of the “new” keyword, and if I don’t inherit, I can’t convert my script into an object.

Edit: This still isn’t working. I’m getting an instance of the class as GameStateManager, but my delegate is never being called, even though it should be called on Awake() in the Intro script. Any ideas?

My manager:

using UnityEngine;
using UnityEngine.Events;
using System.Collections;

public enum GameState {
	INTRO,
	SEARCHING_MATCH,
	PLAYER_ONE_TURN,
	PLAYER_TWO_TURN,
	PLAYER_ONE_WIN,
	PLAYER_TWO_WIN,
	TIE_GAME
}

public delegate void OnStateChangeHandler();


public class GameStateManager : MonoBehaviour {

protected GameStateManager(){}
public static GameStateManager instance = null;
public event OnStateChangeHandler OnStateChange;
public GameState gameState { get; private set; }

public void Awake() 
{
	if (instance == null) 
	{
		instance = this;
		DontDestroyOnLoad(gameObject);
	}
	else if (instance != this)
	{
		DestroyImmediate(gameObject);
	}
}
		

public void setGameState (GameState state) 
{
	this.gameState = state;
	OnStateChange ();
}

public void OnApplicationQuit()
{
	instance = null;
}

}

Intro class:

using UnityEngine;
using UnityEngine.Events;
using System.Collections;

public class Intro : MonoBehaviour {

GameStateManager GM;

void Awake() {
	GM = GameStateManager.instance;
	GM.OnStateChange += HandleOnStateChange;
	Debug.Log ("Current game state when Starts: " + GM.gameState);
}


void Start () {
	Debug.Log ("Current game state when Starts: " + GM.gameState);
}

public void HandleOnStateChange ()
{
	GM.setGameState (GameState.SEARCHING_MATCH);
	Debug.Log ("Handling state changes to: " + GM.gameState);
	Invoke ("LoadLevel", 3f);
}


public void LoadLevel() {
	Application.LoadLevel (1);
}

}

Here’s how I do my GameSession Singleton. You want to use a MonoBehaviour and make sure to place it in the first scene. The implementation below also allows you to put them in other scenes, as they will just delete themselves if they see another one already exists.

public class GameSession : MonoBehaviour
{
    public static GameSession Session { get; private set; }

    public void Start()
    {
        if(Session == null)
        {
            Session = this;
            DontDestroyOnLoad(gameobject);
        }
        else if(Session != this)
        {
            DestroyImmediate(gameobject);
        }
    }
}

You definitely want to edit the script execution order to make sure this runs first though.

The Awake from Intro script is not calling, it is just subscribing the method to the event. You cannot call an event from outside its class.

Now if you manage to call the event, I think you are about to end up in a stack overflow crash.

Let’s say something manages to call setState, then the event is triggered which calls HandleOnStateChange which calls setState which calls the event which calls HandleOnStateChange which calls setState (tell me when to stop) which calls the event…

This will pile up until crash.

Actually, you know what? There would be a second reason for a crash. If LoadLevel would be placed before setState, then it would pile up for 3s and if you have enough memory then it will load the new level and maybe stop the piling process (not sure). But then you have another thing coming, if the event is called again, it will call on all subscribers and the one from Intro is still there despite the Intro object being gone. You need to unregister your events as well.