我对Unity和C#相当陌生,遇到了一些麻烦。我正在设计一个具有多个级别的2D游戏。每个级别都包含一个LevelManager,用于存储该级别是否已完成。他们也有DontDestroyOnLoad命令。我想访问游戏中的所有LevelManager gameObjects,然后将它们存储在关卡选择场景中。我想用赢/输来确定关卡是否已经完成,以便解锁下一个关卡。明确地说,我想要一种方法来访问我的整个游戏中的所有LevelManager,然后将它们作为数组存储在GameManager脚本中。我该怎么办?
首先,不要执行DontDestroyOnLoad-此方法的主要用法是实现诸如unity-singleton(easy-to-use template)之类的事情。这意味着,您将只有一个levelManager实例,而不是每个级别一个。
要以您的方式执行此操作,您需要累加加载所有场景,并获取所有LevelManager实例。或者,您可以一次加载所有场景,从当前LevelManager获取关卡名称及其isPassed值。这可能要花一些时间,而且方法错误。
正确的方法是在ScriptableObject模型中存储场景间数据。它就像一个MonoBehaviour,但与场景无关-它只是放置在项目中的某个位置。
因此,您可以创建名为LevelProgress的ScriptableObject。它将存储所有通过级别的列表。它将具有公共方法LevelPassed(string levelName),您可以使用任何参数作为参数-级别名称,构建中的级别索引,场景本身等等。每当玩家通过任何关卡时,引用了LevelProgress可编写脚本对象的LevelManager(从中删除DontDestoryOnLoad)都会调用LevelProgress.LevelPasses(currentLevel)。然后,如果您需要知道是否通过了某个级别,则可以检查是否是LevelProgress.PassedLevels列表包含该级别。
此外,您需要为此可编写脚本的对象实现会话之间的持久性。 IMO,最好的方法是使用JSONUtility将ScriptableObject转换为JSON字符串,然后将其写入PlayerPrefs。
您可以创建一个ScoreManager
脚本来使用PlayerPrefs存储每个级别的分数,并将此脚本附加到第一个场景中的GameObject。
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;
}
...
}
然后您可以从其他脚本中调用其功能和属性。
...
public void GameOver() {
ScoreManager.Instance.SaveScore(level, score);
}
...
将所有LevelManger脚本与DontDestroyOnLoad一起使用将导致内存泄漏,有时会影响游戏性能。