Unity 3D 使用PlayerPrefs按关卡存储高分出现异常累加的Bug求助

问题根源
- 高分结算、PlayerPrefs读写逻辑全部放在
Update()方法中,没有设置执行时机限制,导致相关逻辑每帧重复运行。 - 你遇到的368分被错误累加为384分的复现场景:
- 玩家触发通关判定的第一帧,计算得到本次对局结算分368,此时读取到的历史高分低于368,触发PlayerPrefs写入,存下368作为当前关卡的已保存高分。
- 通关界面弹出后,因为结算逻辑仍在每帧运行,且没有禁用收集分累加逻辑、没有锁死剩余时间的计算值,某一帧
PlayerController.count又叠加了16的收集分,此时即使剩余时间折算的timePoints略有下降,二者相乘得到的384仍高于已存的368,触发第二次PlayerPrefs写入,把错误的384覆盖为新高分。
- 偶发异常的触发因素:代码中每帧调用
FindObjectOfType<>()获取控制器引用,如果场景中存在多个同类型对象、或者对象生成/销毁的时序错位,会偶发读取到错误的sec/count值,进一步放大数值计算的波动。
修复方案
- 把结算逻辑从
Update()中移出,仅在通关判定触发的瞬间执行一次:- 在玩家碰撞终点触发器、或倒计时归0的判定方法中,单独封装高分结算逻辑,避免每帧重复执行读写操作。
- 结算流程加执行锁:定义
bool isLevelEnded的全局标记,通关后立刻设为true,所有加分、倒计时逻辑检测到该标记为true时直接停止修改数值,避免结算过程中数值动态变化。
- 优化引用获取逻辑:将
TimeController、PlayerController的引用在关卡启动时通过Awake()/Start()缓存,不要每帧重复调用FindObjectOfType<>(),避免引用错配。 - 强制触发PlayerPrefs持久化:存储完成后调用一次
PlayerPrefs.Save(),避免程序异常退出导致存储值丢失。
优化后的核心参考代码:
private bool isLevelCalculated = false; private PlayerController playerCtrl; private TimeController timeCtrl; private void Start() { playerCtrl = FindObjectOfType<PlayerController>(); timeCtrl = FindObjectOfType<TimeController>(); } // 仅在通关触发时调用一次的结算方法 public void OnLevelPass() { if (isLevelCalculated) return; isLevelCalculated = true; int scorePoints = playerCtrl.count; int timePoints; if (timeCtrl.minutes != 0) { timePoints = (timeCtrl.sec + 60)/2; } else { timePoints = timeCtrl.sec/2; } int currentScore = timePoints * scorePoints; string levelKey = SceneManager.GetActiveScene().name; int historyScore = PlayerPrefs.GetInt(levelKey, 0); if (currentScore > historyScore) { PlayerPrefs.SetInt(levelKey, currentScore); PlayerPrefs.Save(); } // 同步通关界面UI显示 scoreDisplay.text = "TOTAL POINTS: " + scorePoints; timeDisplay.text = "TIME LEFT: " + timeCtrl.timeText.text; highScores.text = "HIGH SCORE: " + Mathf.Max(currentScore, historyScore); }
内容的提问来源于stack exchange,提问作者CodingNeeded
相关产品推荐
相关产品推荐

