Skip to main content

三、使用简易对象池优化生成组件时的性能

停下你每次都重新生成的代码,加入一个简易的对象池来优化生成组件时的性能。

在开始这篇 “邪修” 风格的方法教程前,我们先补充一组关键数据:

  • Unity 中生成一个Prefab 实例,通常需要消耗约 1ms 时间;
  • 而在此基础上,若该 Prefab 挂载了 Udon 脚本,Udon 为其生成对应的Udon 虚拟机时,还需额外消耗约 1ms 时间。

这组数据大家可自行测试验证。不难看出,生成 Udon 虚拟机的性能开销相当显著 —— 但实际开发中,很多场景(比如少量、高频复用的简单对象,如临时弹窗、交互道具)并不需要一套功能完备、逻辑复杂的标准对象池。

这种情况下,我更推荐在脚本中直接实现一个简易对象池,以此针对性优化 Udon 虚拟机的 “重复创建 - 销毁” 开销,避免频繁生成新虚拟机带来的性能波动。

这个对象池的写法也很简单,如下:

//以下代码是从实践中复制的,命名啥的就先不管吧,你们看看就好.jpg

//
private int DishQuantity;

public void UpdateShoppingTrolley()
  {
  GeneratedShoppingTrolley(DishQuantity);
  InitShoppingTrolley(DishQuantity);
  }

//生成需要的模块
private void GeneratedShoppingTrolley(int DishQuantity)
        {
            //1:检查需要的按钮数量
            if (DishQuantity > ShoppingTrolleyButtons.Length)
            {
                //创建新数组
                GameObject[] NewShoppingTrolleyButtons = new GameObject[DishQuantity];
                //复制旧数组
                for (int i = 0; i < ShoppingTrolleyButtons.Length; i++)
                {
                    NewShoppingTrolleyButtons[i] = ShoppingTrolleyButtons[i];
                }
                //创建新按钮
                for (int i = ShoppingTrolleyButtons.Length; i < DishQuantity; i++)
                {
                    NewShoppingTrolleyButtons[i] = Instantiate(ShoppingTrolleyButtonPrefab, ShoppingTrolleyButtonParent);
                }
                //替换旧数组
                ShoppingTrolleyButtons = NewShoppingTrolleyButtons;
                //更新购物车按钮
            }
            else if (DishQuantity < ShoppingTrolleyButtons.Length)
            {
                //创建新数组
                GameObject[] NewShoppingTrolleyButtons = new GameObject[DishQuantity];
                //复制旧数组
                for (int i = 0; i < DishQuantity; i++)
                {
                    NewShoppingTrolleyButtons[i] = ShoppingTrolleyButtons[i];
                }
                //删除多余按钮
                for (int i = DishQuantity; i < ShoppingTrolleyButtons.Length; i++)
                {
                    Destroy(ShoppingTrolleyButtons[i].gameObject);
                }
                //更新数组
                ShoppingTrolleyButtons = NewShoppingTrolleyButtons;
            }

  private void InitShoppingTrolley()
    {
    for (int i = 0; i < DishQuantity; i++)
            {
                int ChooseDish = ChooseDishes[i];
                //获取按钮组件
                UdonBehaviour ButtonComponent = ShoppingTrolleyButtons[i].GetComponent<UdonBehaviour>();
                if (ButtonComponent == null)
                {
                    DebugTextUpdate($"购物车按钮组件获取失败:请联系管理员并重新进入世界");
                    continue;
                }
                //设置按钮索引
                ButtonComponent.SetProgramVariable("Index", i);
                ButtonComponent.SetProgramVariable("PlayerUseMenu", this);
                ButtonComponent.SetProgramVariable("DishIndex", ChooseDish);
                //设置按钮名称
                ButtonComponent.SetProgramVariable("DishName", DishName[ChooseDish]);
                //设置按钮数量
                ButtonComponent.SetProgramVariable("DishQuantity", DishPrice[ChooseDish]);
                ButtonComponent.SendCustomEvent("InitButton");
            }

    }

子脚本则通过 InitButton 事件进行初始化,即可完成复用。