Found the answer
How to correctly use a game manager ?
Hi there !
I am new to Unity, and I just finished the tutorial "Roll a Ball", so I am trying to make it better. First of all, having all that GUI inside the PlayerController class is really bad (I am a game dev in Python), so I wanted to put all the code about the game management in an another class. So I created the class GameManager (a singleton, the code is below).
To hold it, I created a class Loader, attached to my Main Camera, and an empty gameobject (I turn it into a prefab) called GameManager.
My GameManager (class) need an access to : some UI elements, and a sound.
But I wanted to have more scenes (I have currently 3 scenes), so I searched some documentation about "How to change the scene in Unity". I'm using Application.loadedLevel to get the current level number, and Application.LoadLevel(levelNumber) to load another level.
But here starts my problem.
If the canvas (which is holding my UI elements) get destroyed, the game manager will try to access to these UI elements, no matter if they don't exist (I don't want to test gameObject != null), and it will raise an error (and it won't work).
So I passed the canvas to my GameManager, and in it Awake() method, I am saying to Unity : DontDestroyOnLoad(canvas)
Yeah ! It's working !!
Err... no. Because I have a canvas (the same each time) in each of my scenes, after the 1st scene, I have 2 canvas ! And Unity doesn'y like it, of course. So it's working correctly. So I created just one canvas in the first scene, but (I think) I need 1 GameManager in each scenes (the gameObject AND the instance of the singleton). And of course (again), it's not working ... Why ? Because the GameManager have no access to the canvas in the scene n°2, but it does in the first (remember, I've just one canvas, in the first scene)
So I don't know at all how to correctly organise my game (1 instance of the gameManager (class) and 1 instance of the game manager (object) in each scene ? 1 canvas per scene ?) and how to solve this bug ...
The errors I have :
NullReferenceException: Object reference not set to an instance of an object GameManager.Prepare () (at Assets/Scripts/GameManager.cs:112) GameManager.InitGame () (at Assets/Scripts/GameManager.cs:122) GameManager.Awake () (at Assets/Scripts/GameManager.cs:103)
(twice)
And then :
ArgumentOutOfRangeException: Argument is out of range. Parameter name: index System.Collections.Generic.List`1[System.Int32].get_Item (Int32 index) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections.Generic/List.cs:633) GameManager.CheckGameFinished () (at Assets/Scripts/GameManager.cs:89) PlayerController.Update () (at Assets/Scripts/PlayerController.cs:35)
(at each frames)
My code :
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
public static GameManager instance = null;
public Text countText;
public Text malusText;
public Text scoreText;
public Image gameOverImage;
public Text gameOverText;
public AudioSource gameOverSound;
public Button previousBtn;
public Button restartBtn;
public Button nextBtn;
public Canvas canvas;
[HideInInspector]
public int pickupsCollected;
[HideInInspector]
public int malusCollected;
[HideInInspector]
public bool gameOver;
[HideInInspector]
public List<int> goals;
public static void UpdateScores () {
GameManager.instance.countText.text = "PickUps : " + getPickups ().ToString ();
GameManager.instance.malusText.text = "Malus : " + getMalus ().ToString ();
GameManager.instance.scoreText.text = "Score : " + CalculateScore ().ToString ();
}
public static int CalculateScore () {
return GameManager.getPickups () - GameManager.getMalus ();
}
public static int getPickups () {
return GameManager.instance.pickupsCollected;
}
public static void CollectedPickup () {
GameManager.instance.pickupsCollected += 1;
}
public static int getMalus () {
return GameManager.instance.malusCollected;
}
public static void TouchAForbiddenObstacle () {
// you touch a wall for example, and so you get a malus ;)
GameManager.instance.malusCollected += 1;
GameManager.UpdateScores ();
}
public static void Falling () {
GameManager.instance.gameOver = true;
}
public void ClickPrevious () {
if (GameManager.CheckGameFinished ()) {
if (Application.loadedLevel > 0) {
Application.LoadLevel (Application.loadedLevel - 1);
}
Debug.Log ("click previous");
Prepare ();
}
}
public void ClickRestart () {
if (GameManager.CheckGameFinished ()) {
Application.LoadLevel (Application.loadedLevel);
Debug.Log ("click restart");
Prepare ();
}
}
public void ClickNext () {
if (GameManager.CheckGameFinished ()) {
if (Application.loadedLevel + 1 < Application.levelCount && GameManager.instance.gameOver == false)
Application.LoadLevel (Application.loadedLevel + 1);
Debug.Log ("click next");
Prepare ();
}
}
public static bool CheckGameFinished () {
return GameManager.instance.pickupsCollected == GameManager.instance.goals[Application.loadedLevel] || GameManager.instance.gameOver;
}
void Awake () {
if (instance == null)
instance = this;
else if (instance != this)
Destroy (gameObject);
DontDestroyOnLoad (gameObject);
Debug.developerConsoleVisible = true;
Debug.Log ("Starting");
InitGame ();
}
void Prepare () {
pickupsCollected = 0;
malusCollected = 0;
gameOver = false;
gameOverImage.gameObject.SetActive (false);
gameOverText.gameObject.SetActive (false);
restartBtn.gameObject.SetActive (false);
previousBtn.gameObject.SetActive (false);
nextBtn.gameObject.SetActive (false);
Debug.Log ("preparing");
}
void InitGame () {
Prepare ();
goals = new List<int> ();
goals.Add (8);
goals.Add (9);
goals.Add (11);
DontDestroyOnLoad (canvas);
DontDestroyOnLoad (gameOverSound.gameObject);
Debug.Log ("loading");
}
void Update () {
if (CheckGameFinished ()) {
gameOverImage.gameObject.SetActive (true);
gameOverText.gameObject.SetActive (true);
gameOverSound.Play ();
restartBtn.gameObject.SetActive (true);
if (gameOver == false && malusCollected == 0)
nextBtn.gameObject.SetActive (true);
if (Application.loadedLevel > 0)
previousBtn.gameObject.SetActive (true);
}
}
}
Follow this Question
Related Questions
Text object used in script gets deleted in inspector when running the game. (Gifs inside question) 0 Answers
Help with Enabling GameObject in Inspector. 1 Answer
Hierarchy objects deleted and 999+ errors when adding terrain 0 Answers
Compiler Error, Cannot Go Into Playmode 2 Answers
HELP!! unexpected token: If 1 Answer