- Home /
Help to understand events and delegates (Game Manager)
Hi everyone, I'm new to Unity so I have a lot to learn..
I'm trying to set up a game manager for my game, I have been following this tutorial and understood most of it: https://hub.packtpub.com/creating-simple-gamemanager-using-unity3d/
Now, as per the tutorial, I have a game manager script that is a Singleton, and I have a scene called Intro, that has an empty gameobject with an Intro.cs script.
The issue I have is that when I run the game, the Intro script executes Awake and Start, but the ChangeState function is not either called, or passed to the delegate (not sure about the correct wording). I cannot really tell where the problem is, and I hope you guys can help me understanding it.
GameManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//list of game states
public enum GameState { INTRO, MAIN_MENU }
//callback to change the gameState
public delegate void OnStateChangeHandler();
public class GameManager
{
protected GameManager() {}
static GameManager instance = null; //global variable where the gm instance is stored
public event OnStateChangeHandler OnStateChange; //event to change state
public GameState gameState { get; private set; } //getter for the current game state
//getter for the gm instance
public static GameManager Instance{
get {
if (GameManager.instance == null) { //if there is no instance, create one
GameManager.instance = new GameManager();
}
return GameManager.instance; //returns the instance
}
}
//function to change the state
public void SetGameState(GameState state) {
this.gameState = state;
OnStateChange();
}
public void OnApplicationQuit() {
GameManager.instance = null;
}
}
Intro.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Intro : MonoBehaviour
{
GameManager gm;
void Awake() {
gm = GameManager.Instance;
gm.OnStateChange += ChangeState;
Debug.Log("Awake - current state: " + gm.gameState);
}
void Start() {
Debug.Log("Start - current state: " + gm.gameState);
}
public void ChangeState() {
gm.SetGameState(GameState.MAIN_MENU);
Debug.Log("About to change state to: " + gm.gameState);
Invoke("LoadLevel", 2f);
}
public void LoadLevel() {
SceneManager.LoadScene(1);
}
}
Thanks for your support!
Don't bother with creating custom delegates. You can use System.Action
for all kinds of callbacks. If you need it to have arguments use System.Action<T>
.
Answer by T27M · Oct 19, 2020 at 09:21 AM
To start off the code you are looking in the article seems to have a bug, which is fixed in the Github repo https://github.com/bttfgames/SimpleGameManager/tree/master/Assets/Scripts (I'll leave that as a small challenge for you to figure out ;) ) However, your problem is that you have no calls to invoke the SetGameState method in your GameManager. If you follow the tutorial to completion this is done in the Menus.cs script.
To explain a little further, the Intro.cs script is a listener to the OnStateChange event. In your Awake method you subscribed to the event with the following code:
gm.OnStateChange += ChangeState;
This doesn't invoke the ChangeState method. What you are essentially saying is when the OnStateChange event is "fired" I want to know about it and to handle that event I will call a function on my script i.e ChangeState()
Additionally, you are subscribing to the event and then also calling gm.SetGameState() if you think about it, in this context, this doesn't really make sense. The event is telling you that the game state has changed and then you are calling the GameManager to tell it to change state (there are possible cases where this may be valid, but it's a little out of the scope of this tutorial).
Answer by Yagami93 · Oct 19, 2020 at 12:47 PM
I see now, I was actually calling the ChangeState() within the very same function, that's why it doesn't make much sense and nothing happens.
I moved the gm.SetGameState() in the start function, like in the repo you kindly linked, and now it works as intended.
Thank you very much!