- Home /
How to create a main menu with singleton pattern?
Hello everyone, I am new both to this forum and Unity, so please bare with me, my understanding of this might not be the best. I am using a game manager to manage my game data (lives, score, position in player prefs) and game scenes. My GameManagerObject is in the game scene and I created a singleton pattern in awake method of game manager script. In order to switch to game over or win scene after the player dies or wins, I am using OnSceneLoaded method, and also enabling it in Awake. Now my question is, how do I implement a main menu, or create a retry button on game over scene which will lead to my game scene again, as the singleton won't let me execute the start method the second time? Basically, I believe because of singleton, when my game is run directly from the scene everything runs accordingly, but when I load the game through another scene I am getting an error saying that the GameObjectManager has been destroyed.
I also had an issue where the playerPrefs "weren't loading" when starting the game from another scene (e.g. player lives were null), and now I managed to fix it but they are still not saving and loading.
This a part of my code. Disclaimer, I am supposed to use a singleton so I'm mainly searching for solutions including its use.. Thanks
private void Awake()
{
//singleton
if (_instance == null)
{
_instance = this;
}
else if (_instance != this)
{
Destroy(this.gameObject);
}
SceneManager.sceneLoaded += OnSceneLoaded; //for gameover
DontDestroyOnLoad(this.gameObject);
}
void Start()
{
//there's more but basically loading and displaying data
GetComponent<SaveLoadManager>().LoadData();
}
And these are my GameOver and Win scenes.
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (scene.name == "GameOver" || scene.name == "Win")
{
Text scoretext = GameObject.Find("Scoretext").GetComponent<Text>();
scoretext.text = "score: " + GameData.GameScore.ToString();
if (GameData.GameScore > GameData.HighScore) GameData.HighScore = GameData.GameScore;
Text highscoretext = GameObject.Find("Highscore").GetComponent<Text>();
highscoretext.text = "highest score: " + GameData.HighScore.ToString();
//also displaying and saving newly set data
}
Answer by Beacom · Jan 15 at 08:04 PM
Is there a reason not to call LoadData() in either the Awake() function or OnSceneLoaded() function? Your singleton setup looks good. As you stated Start() is only executed once, so I think you just need to move any logic you have in Start() that needs multiple executions to a function that will be called when appropriate.
I tried placing the necessary code in another function instead of inside Start() and calling it when the Game scene is loaded, I even used code to check if the scene is loaded first to prevent returning null values, but it didn't seem to work. When being called from Awake() it does work, but doesn't load saved data, just sets and displays its values to what I stated in the script itself.
Answer by rh_galaxy · Jan 16 at 04:07 AM
I think in Awake() you should return after destroying the object, and also be aware that destroying the object will make OnDestroy() get called, so don't do any deinit there, have it empty.
else if (_instance != this)
{
Destroy(this.gameObject); //be careful, calls OnDestroy()
return;
}
//the rest is done once only...
//...
I'm unsure if Start() is called the second time after Awake, try having it like the other answer says when you want data to be loaded.