二、在实时和性能之间取得平衡
其实十分的简单这个问题——既然我们的需求是尽可能实时的获得其他脚本的变量信息,比如著名的UdonChips钱包系统,如果我们需要为其打造一款全新的插件,我们需要去持续的更新钱包的钱数以保证其他的模块能正常运行。对此UdonChips的官方解决方案是——通过在Update方法下每一帧检查钱包脚本的指定参数与本地的备份是否有区别。还在滥用Update来获取其他脚本变量?邪修助你在实时和性能之间取得平衡。
这个问题的核心需求其实很明确 —— 我们需要尽可能实时地获取其他脚本的变量信息。比如在 UdonChips 钱包系统中,若要为其开发全新插件,就必须实时更新钱包余额,才能确保消费、查询等关联模块正常运行。对此,UdonChips 的官方解决方案是:在Update方法中,通过每一帧检查钱包脚本的指定变量与本地备份是否存在差异,以此实现变量的实时同步。
在为了优化性能表现,我将其进行了一点点改造,并且将其他模块的Update事件更改为了一个静态事件,解决了这个问题:这种方案虽能满足基础需求,但高频的帧级轮询会带来不必要的性能开销。为优化性能表现,我对该逻辑做了针对性改造,核心是将 “其他模块依赖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;
}