Unity每秒发放游戏金币逻辑重复执行两次的Bug排查修复
问题原因
重复发货币的Bug确实和static的使用方式直接相关,核心触发逻辑是:
- 你当前场景里存在至少2个挂载了
PlayerStats脚本的GameObject实例
static修饰的money/income/soldiers是类级别的全局变量,所有PlayerStats实例都会读写同一份值,但每个挂载在对象上的脚本实例,都会独立执行Unity的生命周期函数Update()。两个实例就会每秒各触发一次发钱逻辑,相当于每秒给共享的money变量加两次收入,同时income也会被多扣1点,和你观察到的现象完全吻合。 - 常见的多实例来源:要么是编辑场景时不小心给多个对象拖了同一个脚本,要么是切场景时没有销毁原有PlayerStats对象,新场景加载时又生成了一个新的挂载脚本的对象。
- 额外代码问题:给static字段加
[SerializeField]没有任何作用,Unity的序列化系统不支持静态变量,Inspector面板上对这几个字段的修改不会生效,运行时永远会读取Start里赋值的初始值。 - 你写的
nextUpdate计时逻辑在极端低帧率下有单帧多次触发的边界问题,但不会导致稳定的每次发两次的现象。
修复步骤
- 先排查现有重复实例
运行状态下在Hierarchy面板搜索框输入t:PlayerStats,会列出所有挂载了该脚本的对象,删除多余的对象,只保留一个即可。 - 加单实例保护,从根源避免多实例问题
给脚本添加单例校验,多余的实例生成时直接销毁,同时支持切场景不销毁,避免加载场景时重复生成,修改后的代码如下:
using UnityEngine; public class PlayerStats : MonoBehaviour { public static PlayerStats Instance; public static int soldiers; public static int money; public static int income; private int nextUpdate = 1; void Awake() { // 已存在实例时直接销毁当前多余对象 if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; // 切场景时保留该对象,避免重复加载生成 DontDestroyOnLoad(gameObject); } void Start() { income = 500; money = 2500; soldiers = 20; } void Update() { if(Time.time >= nextUpdate) { nextUpdate = Mathf.FloorToInt(Time.time) + 1; UpdateEverySecond(); } } void UpdateEverySecond() { GetMoney(); DecreaseIncome(); } void GetMoney() { money += income; } void DecreaseIncome() { if (income >= 0) { income -= 1; } } }
- 可选优化:替换计时逻辑
自己在Update里写时间判断容易出边界问题,可以直接用Unity自带的定时调用,删掉Update方法和nextUpdate变量,在Start里加一句InvokeRepeating(nameof(UpdateEverySecond), 1f, 1f);,就能稳定每秒执行一次逻辑,不用手动维护计时变量。
注意:static只会保证字段是全局共享的同一份数据,不会让脚本的生命周期函数只执行一次,多个脚本实例同时操作同一份静态数据,必然会出现重复执行、数值计算错误的问题。
内容的提问来源于stack exchange,提问作者Tcq
相关产品推荐
相关产品推荐

