Game Manager Help

Hello community. I am new to Unity and attempting to put together a game that I had previously written in C++ using some middleware that ended up being less than promissed. As a result my employers decided I would rebuild it in Unity. Unfortunately I know nothing about it. I have absorbed hours and hours of video tutorials, I have purchased SpriteManager2 and EZGUI (which are amazing, tip of the hat to Brady from Above and Beyond Software). The basic gameplay I can manage, I have that going, and it was nice and easy (relatively speaking). However I am trying to write a Game Manager that will handle changing between menu and game states, keep track of scores etc. The game is quite simple, it’s a forced runner (picture Robot Unicorn) where you have one life and just have to keep running, dodging and jumping obstacles, to get the highest score (or longest distance if you like).

I found some manager scripts at Silent Kraken (http://www.blog.silentkraken.com/2010/06/22/unity3d-manager-systems/) which are great, but I can’t get them working. Let me show you what I have at the moment.

I have a “ManagerManager” script. This is a persistant gameobject that does not get destroyed between scenes (hopefully that’s what will happen). It looks like this:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(GameManager))]
[RequireComponent(typeof(AudioManager))]

public class ManagerManager : MonoBehaviour
{
	#region Members
	private static GameManager m_gameManager;
	public static GameManager m_game
	{
		get { return m_gameManager; }
	}
	
	private static AudioManager m_audioManager;
	public static AudioManager m_audio
	{
		get { return m_audioManager; }
	}
	
	#endregion
	
	#region Functions
	// Use this for initialization
	void Awake ()
	{
		//find the references
		m_gameManager = GetComponent<GameManager>();
		m_audioManager = GetComponent<AudioManager>();
		
		//make this object persistent
		DontDestroyOnLoad(this);
	}

	
	#endregion
}

It basically just holds all the other managers that I might need. In this case just a game manager (that handles game states) and an audio manager.

The game manager looks like this:

using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour
{
	
	#region Members
	private GameState m_curState;
	public GameState m_state
	{
		get { return m_curState; }
	}
	
	#endregion
	
	#region Functions

    void Start()
    {
        SetState(typeof(MenuState));
        Debug.Log("We are in the game manager start function");
    }
	
	void Update()
	{
		if(m_curState != null)
		{
            Debug.Log("The current state : " + m_curState.name);
			m_curState.OnUpdate();
		}
	}
	

    //changes the current game state
    public void SetState(System.Type newStateType)
    {
        Debug.Log("In SetState()");
        if (m_curState != null)
        {
            m_curState.OnDeactivate();
        }

        m_curState = GetComponentInChildren(newStateType) as GameState;
        Debug.Log("The current state is: " + m_curState.name);
       
        if (m_curState != null)
        {
            m_curState.OnActivate();
        }
    }
	
	#endregion
}

This is the one that I’m having trouble with. It seems fine to me, but when it’s running it does some crazy things.
You will see I have debug lines in a few places, attempting to debug the script (as a c++ coder I struggle with not being able to step through code at run time). For some reason the very first line to get written is the one in SetState() not the one in Start().
This boggles me.
Then it Updates the first state (which is a menu state). Here is the menu state:

using UnityEngine;
using System.Collections;

public class MenuState : GameState
{
	#region Members
	float timer = 0.0f;
	#endregion
	
	#region Funtions
	public override void OnActivate()
	{
		Application.LoadLevel("Menu");
        Debug.Log("OnActivate called in MenuState");
	}
	
	public override void OnDeactivate()
	{
		
	}
	
	public override void OnUpdate()
	{
		Debug.Log("Current time is: " + timer);
		timer += Time.deltaTime;
		
		if(timer >= 120)
		{
			ManagerManager.m_game.SetState(typeof(PlayState));			
		}
	}
	#endregion
}

this derives from an abstract state class that just has empty activate, deactivate and update functions. Basically this should just count down for 2 minutes then change the state to another one.
This doesn’t happen. The very next line in my debug console after the MenuState’s OnActivate() is the GameManager’s Start() function, which I thought should have been called first, and I have no idea how it’s being called now. Then the MenuState’s OnUpdate() is called, then somewho SetState() is called again.

In Unity there are multiple ManagerManager objects being created every update or so. I cannot decipher what is happening here.

If that wasn’t too confusing then hopefully someone will be able to give me a nudge in the right direction here.
Thank you in advance for your help.

Adam

Damn. I have been looking at this over and over and been completely unable to find a solution. Then, as always happens to me, I finally decide to post the question and as soon as I do, while I look over it for the millionth time waiting for a possible reply, I find the solution myself. The scene Menu was already loaded, it was the one I started in, but the MenuState loaded it in OnActivate, which started the whole loop again. A simple check before loading it (if(Application.loadedLevelName != “Menu”) and that solved the problem. As for the strange order of things, you’ll notice I had the Debug.Log line after the SetState() call in the GameManagers Start() function, so it was logging the line inside SetState() before returning to Start() and logging that one out. Just dodgy on my side there. Need to pay attention. Well then, in that case I hope the above classes help someone else out. I haven’t finished testing them, so I may be posting here again very soon :wink:

You can actually debug using MonoDevelop. It’s a little unstable (or at least I’ve found that to be the case), but it does work.

really? it allows you to step through line by line while it’s running?

I have hit another problem. IT appears to be working, but m_curState isn’t holding its value. It reverts to MenuState. I can’t see any reason for it. It runs perfectly, the timer runs out (incidently I changed it to 10 seconds for debugging, no idea why I chose 2 minutes in the first place) and the scene changes, my ManagerManager survives the change with all the managers that are children of it. But the very first time update() is called on the GameManager after the scene chage the current state is MenuState again. The only time SetState() is called with MenuState as an argument is on the ManagerManager classes Start() function and this isn’t being called. I have logged traces all through the program, no extra function calls are happening, it must be something to do with the change to m_curState happening in the previous scene and not carrying over.

Any ideas?

Yup. Like I said, I’ve found it be a bit unstable at times, but nevertheless it’s fairly effective.

As I understand it, to debug, you have to do the following:

  1. Make sure MonoDevelop is open but Unity is not open.

  2. In MonoDevelop, choose ‘Debug’ from the ‘Run’ menu.

Once Unity opens, if you set a breakpoint and enter play mode, if the breakpoint is hit, playback should pause and MonoDevelop should flash in the task bar (or otherwise get your attention), at which point you can switch to it and proceed with debugging.

Im updating the code on this post to what I have currently. This works in every way except as mentioned above. Oddly the log shows that there are times when the SetState() function is being called and the previous state was already the PlayState. Anyway, check out all the classes:

ManagerManager:

using UnityEngine;

using System.Collections;



//[RequireComponent(typeof(GameManager))]

//[RequireComponent(typeof(AudioManager))]



public class ManagerManager : MonoBehaviour

{

	#region Members

	private static GameManager m_gameManager;

	public static GameManager m_game

	{

		get { return m_gameManager; }

	}

	

	private static AudioManager m_audioManager;

	public static AudioManager m_audio

	{

		get { return m_audioManager; }

	}

	

	#endregion

	

	#region Functions

	// Use this for initialization

	void Awake ()

	{

		//find the references

		m_gameManager = GetComponent<GameManager>();

		m_audioManager = GetComponent<AudioManager>();

		

		//make this object persistent

		DontDestroyOnLoad(this);

	}



	

	#endregion

}

Game Manager:

using UnityEngine;

using System.Collections;



public class GameManager : MonoBehaviour

{

	

	#region Members

	private GameState m_curState;

	public GameState m_state

	{

		get { return m_curState; }

	}

	

	#endregion

	

	#region Functions



    void Start()

    {

        Debug.Log("We are in the game manager start function");

        SetState(typeof(MenuState));        

    }

	

	void Update()

	{

		if(m_curState != null)

		{

            Debug.Log("Update() called in GameMaanger");

            Debug.Log("Current state is " + m_curState.name);

			m_curState.OnUpdate();

		}

	}

	



    //changes the current game state

    public void SetState(System.Type newStateType)

    {

        Debug.Log("SetState() called in GameManager");

        if (m_curState != null)

        {

            m_curState.OnDeactivate();

        }

        if(m_curState != null)

        {

            Debug.Log("m_curState was: " + m_curState.name);

        }

        

        m_curState = GetComponentInChildren(newStateType) as GameState;

        

        if (m_curState != null)

        {

            Debug.Log("m_curState is now: " + m_curState.name);

        }

        

        if (m_curState != null)

        {

            m_curState.OnActivate();

        }

    }

	

	#endregion

}

Abstract State Class:

using UnityEngine;

using System.Collections;



public abstract class GameState : MonoBehaviour

{

	#region Members

	

	#endregion

	

	#region Functions

	

	public abstract void OnActivate();

	public abstract void OnDeactivate();

	public abstract void OnUpdate();

	

	#endregion

}

Menu State derived from Abstract Game State above:

using UnityEngine;

using System.Collections;



public class MenuState : GameState

{

	#region Members

	float timer = 0.0f;

	#endregion

	

	#region Funtions

	public override void OnActivate()

	{

        if(Application.loadedLevelName != "Menu")

        {

		    Application.LoadLevel("Menu");

        }

        Debug.Log("OnActivate() called in MenuState");

	}

	

	public override void OnDeactivate()

	{

        Debug.Log("OnDeactivate() called in MenuState");

	}

	

	public override void OnUpdate()

	{

		Debug.Log("Current time is: " + timer);

		timer += Time.deltaTime;

		

		if(timer >= 10)

		{

			ManagerManager.m_game.SetState(typeof(PlayState));			

		}

	}

	#endregion

}

Play State derived from Abstract Game State above:

using UnityEngine;

using System.Collections;



public class PlayState : GameState

{



	#region Members

	

	#endregion

	

	#region Functions

	public override void OnActivate()

	{

        if(Application.loadedLevelName != "Game")

        {

		    Application.LoadLevel("Game");

        }

        Debug.Log("OnActivate() called in PlayState");

	}

	

	public override void OnDeactivate()

	{

        Debug.Log("OnDeactivate() called in PlayState");

	}

	

	public override void OnUpdate()

	{

		Debug.Log("OnUpdate() called in PlayState");

	}

	

	#endregion

	

}

So the debug log looks something like this:

Ok, so that probably isn’t very clear, but after the Current Time value goes over 10 the state should change to PlayState and just stay there. Somehow the state is being changed back to Menu after it has got into PlayState

All of that basically says that every second update the GameManager is updating the MenuState instead of the PlayState.