Skip to main content

二、在实时和性能之间取得平衡

还在滥用Update来获取其他脚本变量?邪修助你在实时和性能之间取得平衡。

这个问题的核心需求其实很明确 —— 我们需要尽可能实时地获取其他脚本的变量信息。比如在 UdonChips 钱包系统中,若要为其开发全新插件,就必须实时更新钱包余额,才能确保消费、查询等关联模块正常运行。对此,UdonChips 的官方解决方案是:在Update方法中,通过每一帧检查钱包脚本的指定变量与本地备份是否存在差异,以此实现变量的实时同步。

这种方案虽能满足基础需求,但高频的帧级轮询会带来不必要的性能开销。为优化性能表现,我对该逻辑做了针对性改造,核心是将 “其他模块依赖Update轮询” 的模式,替换为 “主脚本主动推送的静态事件”,具体解决方案如下:

解决方案:

  1. 注册阶段:子脚本(如钱包插件的消费模块、余额显示模块)在初始化时,主动向主脚本(如 UdonChips 钱包核心脚本)注册自身的 “变量更新回调事件”,完成 “订阅” 关联;
  2. 触发阶段:主脚本仅在自身指定变量(如钱包余额)发生实际更改时,才触发预设的静态事件,并向所有已注册的子脚本主动推送变量更新信号;
  3. 接收阶段:子脚本无需再通过Update轮询,只需预先按照规范定义好 “接收更新信号的处理逻辑”,即可在收到主脚本推送时,实时响应并获取最新变量信息。

主脚本(核心脚本):


//注册
public void RegisterOnMoneyChanged(GameObject target)
		{
			// 检查目标是否为UdonBehaviour
			UdonBehaviour udonBehaviour = target.GetComponent<UdonBehaviour>();
			if (udonBehaviour == null)
			{
				Debug.LogError("目标 GameObject 没有 UdonBehaviour 组件");
				return;
			}
			if (Target == null)
			{
				Target = new UdonBehaviour[0];
			}
			UdonBehaviour[] newTarget = new UdonBehaviour[Target.Length + 1];
			for (int i = 0; i < Target.Length; i++)
			{
				newTarget[i] = Target[i];
			}
			newTarget[Target.Length] = udonBehaviour;
			Target = newTarget;
			//注册Debug
			if (NewCodeDebugMode)
			{ Debug.Log("注册成功:" + target.name); }
		}

//添加-减少参数
public void ChangeMoneyAndUpdate(float Value)
		{
			money += Value;
			NotifyMoneyChanged();
		}

//发送事件
private void NotifyMoneyChanged()
		{
			if (NewCodeDebugMode)
			{ Debug.Log("金额发生更改"); }
			for (int i = 0; i < Target.Length; i++)
			{
				Target[i].SendCustomEvent("UdonChipsMoneyChanged");
			}
		}

子脚本(功能脚本)

public void start()
      {
        //获取UdonChips组件
        udonChips = GameObject.Find("UdonChips").GetComponent<UdonChips>();
        //注册为需要更新的组件
        udonChips.RegisterOnMoneyChanged(this.gameObject);
        }  

public void UdonChipsMoneyChanged()
        {
          currentMoney = udonChips.money;
        }