Unity关卡选择场景中如何保存关卡最佳通关时长?
解决方案步骤
一、最佳时长的存储与更新逻辑
用PlayerPrefs存储每个关卡的最佳时长,它适合存储简单键值对数据,无需复杂序列化。通关时对比当前耗时与存储的最佳时长,首次通关直接保存,耗时更短时覆盖原数据。
// 在关卡通关逻辑中调用此方法 public void UpdateBestTime(int levelIndex, float currentTime) { string key = $"BestTime_Level{levelIndex}"; if (PlayerPrefs.HasKey(key)) { float bestTime = PlayerPrefs.GetFloat(key); if (currentTime < bestTime) { PlayerPrefs.SetFloat(key, currentTime); PlayerPrefs.Save(); // 立即保存避免数据丢失 } } else { PlayerPrefs.SetFloat(key, currentTime); PlayerPrefs.Save(); } }
二、关卡选择场景展示最佳时长
在关卡选择场景的UI文本组件中,加载对应关卡的最佳时长,无通关记录时显示提示文本。
// 关卡选择场景的UI脚本 public class LevelSelectUI : MonoBehaviour { public Text[] levelTimeTexts; // 每个关卡对应的显示文本 void Start() { LoadAllBestTimes(); } void LoadAllBestTimes() { for (int i = 0; i < levelTimeTexts.Length; i++) { int levelIndex = i + 1; // 假设关卡从1开始编号 string key = $"BestTime_Level{levelIndex}"; if (PlayerPrefs.HasKey(key)) { float bestTime = PlayerPrefs.GetFloat(key); // 格式化时间为分:秒.毫秒格式 string timeStr = string.Format("{0:00}:{1:00}.{2:00}", Mathf.Floor(bestTime / 60), Mathf.Floor(bestTime % 60), Mathf.Floor((bestTime * 100) % 100)); levelTimeTexts[i].text = $"最佳时长: {timeStr}"; } else { levelTimeTexts[i].text = "未通关"; } } } }
三、解决关卡选择场景计时器重置问题
问题根源是计时器脚本在非游戏关卡场景也启动了计时,以下两种方案可解决:
方案1:场景名称判断
通过当前场景名称识别是否为游戏关卡,仅在关卡场景开启计时:
public class LevelTimer : MonoBehaviour { private float currentTime; private bool isTiming; void Start() { // 假设游戏关卡场景名称包含"Level",如"Level1"、"Level2" if (SceneManager.GetActiveScene().name.Contains("Level")) { isTiming = true; currentTime = 0; } else { isTiming = false; } } void Update() { if (isTiming) { currentTime += Time.deltaTime; } } // 通关时调用,传入当前关卡索引 public void OnLevelComplete(int levelIndex) { isTiming = false; UpdateBestTime(levelIndex, currentTime); } }
方案2:全局状态控制
用静态类管理游戏状态,精准控制计时开关:
// 全局静态类,管理游戏状态 public static class GameState { public static bool IsInGameLevel { get; set; } } // 关卡加载脚本 public class LevelLoader : MonoBehaviour { public void LoadLevel(int levelIndex) { GameState.IsInGameLevel = true; SceneManager.LoadScene($"Level{levelIndex}"); } public void LoadLevelSelect() { GameState.IsInGameLevel = false; SceneManager.LoadScene("LevelSelect"); } } // 计时器脚本 public class LevelTimer : MonoBehaviour { private float currentTime; void Update() { if (GameState.IsInGameLevel) { currentTime += Time.deltaTime; } } public void OnLevelComplete(int levelIndex) { GameState.IsInGameLevel = false; UpdateBestTime(levelIndex, currentTime); } }
额外注意事项
- 测试时可调用
PlayerPrefs.DeleteAll()清空测试数据; - 若需多用户存档,可改用
JsonUtility序列化到本地文件,单用户场景下PlayerPrefs足够; - 计时器脚本若需跨场景保留,可添加
DontDestroyOnLoad并实现单例模式避免重复实例化。
内容的提问来源于stack exchange,提问作者AvaloN
相关产品推荐
相关产品推荐

