- Home /
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);
}
}
Answer by fafase · Jun 18, 2015 at 06:54 PM
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.
Answer by FortisVenaliter · Jun 11, 2015 at 09:15 PM
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.
I might be over complicating my implementation of the Singleton, and I'll probably simplify it to more or less what you have eventually. $$anonymous$$y bigger issue is that my delegate is not handling my state information and I can't figure out why.
Yeah, I'm betting it's a reference issue. Use some debug.logs to ensure the references are all set properly. $$anonymous$$y suggested implementation keeps references simple.
I'm getting an instance of the GameState$$anonymous$$anager. The gameState isn't null, because it's printing the current gameState in my Intro script.
The only thing that isn't happening is the HandleOnStateChange method. On awake the G$$anonymous$$.onStateChange += HandleOnStateChange should take care of that though, shouldn't it?
I ended up simplifying my code, but I'm running into the same problem. An instance of the GS$$anonymous$$, but the state never changes, and the delegate is never called.
Your answer
Follow this Question
Related Questions
GameManager and scene design issue. 1 Answer
Unity book for programmers 6 Answers
[Solved] Help with my music manager 1 Answer
Singletons in multiplayer games 1 Answer
Help to understand events and delegates (Game Manager) 2 Answers