I am fairly new to Unity and C# and am having some trouble. I am designing a 2d game, which has multiple levels. Each level contains a LevelManager which stores whether the leve
First, DontDestroyOnLoad is not supposed to do this - main usage for this is to implement things like unity-singleton (easy-to-use template). It means, you`ll have one instance of levelManager, not one per level.
To do it in your way, you need to load all the scenes additively, and get all the LevelManager instances. Or you can load all scenes one-by-one, getting level name and it`s isPassed value from current LevelManager. It can take a while, and its a wrong way.
The right way is to store inter-scene data in ScriptableObject models. It`s like a MonoBehaviour, but not related to scene - it just lays somewhere in project.
So, in your case, you can create ScriptableObject called LevelProgress. It will store the list of all passed levels. It will have public method LevelPassed(string levelName), as a parameter you can use anything - levels name, levels index in build, scene itself, whatever. Every time, when player passes any level, your LevelManager (remove DontDestoryOnLoad from it), which has a reference to LevelProgress scriptable object, will call LevelProgress.LevelPasses(currentLevel). And then, if you need to know, was some level passed, or not, you can just check, is LevelProgress.PassedLevels list contains this level.
Additionally, you need to implement between-sessions persistance for this scriptable object. IMO, the best way for this is to use JSONUtility to convert ScriptableObject into JSON string, and then write it to PlayerPrefs.
You can create a ScoreManager
script to store scores of each level using PlayerPrefs and attach this script to a GameObject in the first scene.
public class ScoreManager: MonoBehavior {
public static ScoreManager Instance;
const string LEVEL_KEY = "SCORE_";
const string MAX_LEVEL_KEY = "MAX_LEVEL";
public static int MAX_LEVEL {
get { return PlayerPrefs.GetInt(MAX_LEVEL_KEY, 1); }
set {
if(value > MAX_LEVEL) {
PlayerPrefs.SetInt(MAX_LEVEL_KEY, value);
}
}
}
void Awake() {
if(Instance != null) {
Destroy(this.gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(this);
}
public void SaveScore(int level, float score) {
PlayerPrefs.SetFloat(LEVEL_KEY + level, score);
MAX_LEVEL = level;
}
public float GetScore(int level) {
return PlayerPrefs.GetFloat(LEVEL_KEY + level, 0);
}
public bool IsLevelUnlocked(int level) {
// You can write your own level-unlock logic here.
return level <= MAX_LEVEL;
}
...
}
Then you can just call its functions and properties from other scripts.
...
public void GameOver() {
ScoreManager.Instance.SaveScore(level, score);
}
...
Having all LevelManger scripts with DontDestroyOnLoad will cause a memory leak and sometimes it will affect the game performance.
I seemed to have figured it out. I created a gameObject containing a GameManagement script, that had the DontDestroyOnLoad line. I had also added a specific tag. I then searched for that object in each level and updated my values to that. The GameManagement script had an array of bools for levels completed and levels unlocked. Each levelmanager decided whether the level was won and updated that. Using that I determined what level was unlocked. I did though need to use Fire King's Awake Command. It ensures that there are no other copies of the script in the game. Solves my problems.