You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中Update调用GameObject.FindGameObjects的性能开销及优化方案

磁铁收集金币的性能优化问题

我正在开发一款游戏,需要实现玩家用磁铁收集金币的功能,以下是金币生成代码:

// Spawn Coins In Air
void SpawnCoinsInAir ()
{
  float yPos = transform.position.y + 1f;
  float zPos = transform.position.z + 4f;
  for (int i = 0 ; i < 10 ; i += 1)
  {
    int line =  i == 0 ? 
    RandomsPlayerController.Instance.CurrentLineIdx 
    :
    Random.Range(0, RandomsPlayerController.Instance.Lines.Count);

    for (int j = 0 ; j < Random.Range(3,6) ; j += 1) 
    {
      zPos += j + 10f;
      var it = Instantiate(
       coinTransform,
       new Vector3(RandomsPlayerController.Instance.Lines [line].x,yPos , zPos),
        Quaternion.identity
      );

      // 随机Y轴旋转
      it.transform.DORotate (
        Utilities.VectorY (Vector3.zero, Random.Range(-360,360)),
        1f,
        RotateMode.FastBeyond360
      )
      .SetEase (Ease.InOutSine);

      Destroy (it, actionDuration + 1f);
    }
  }
}

目前游戏中已生成所有金币,我需要通过标签查找每个金币并按最短距离收集。我想了解在Update函数中调用GameObject.FindGameObjectsWithTag查找所有金币的性能开销是多少,以及是否有兼顾性能的实现方法?以下是当前实现代码:

private void UseMagnet ()
{
  // 收集金币
  foreach (var coin in  GameObject.FindGameObjectsWithTag ("coin")) continue;
}

private void Update () => UseMagnet();

关于GameObject.FindGameObjectsWithTag在Update中的性能开销

  • GameObject.FindGameObjectsWithTag每次调用都会遍历整个场景内所有活跃的GameObject,逐一检查标签是否匹配。如果场景中金币数量较多(几十上百个),再加上其他大量场景对象,每帧调用会带来明显的CPU占用,直接导致帧率下降。
  • 这种遍历是同步阻塞主线程的,在移动平台等CPU性能有限的设备上,性能问题会被进一步放大。

兼顾性能的实现方法

1. 维护全局金币列表(推荐方案)

在金币生成和销毁时自动维护列表,彻底避免每帧遍历场景:

  • 创建一个单例管理器(比如CoinManager),用List<GameObject>或HashSet<GameObject>存储所有活跃金币。
  • 修改金币生成代码,实例化后将金币加入列表:
    var it = Instantiate(...);
    CoinManager.Instance.AddCoin(it);
    
  • 在金币的脚本中通过OnDestroy回调,从列表中移除自身:
    void OnDestroy()
    {
        CoinManager.Instance.RemoveCoin(gameObject);
    }
    
  • 后续在UseMagnet中直接遍历该列表,还能快速按距离排序:
    private void UseMagnet ()
    {
        var sortedCoins = CoinManager.Instance.ActiveCoins
            .OrderBy(coin => Vector3.Distance(transform.position, coin.transform.position))
            .ToList();
        
        foreach (var coin in sortedCoins)
        {
            // 执行金币收集逻辑(比如移动到玩家位置)
            // ...
        }
    }
    

2. 减少查找调用频率

如果磁铁并非持续激活,仅在玩家触发技能期间执行查找(或处理列表),而不是每帧调用:

  • 给磁铁设置激活状态标记,只有标记为激活时才执行收集逻辑,避免无意义的每帧运算。

3. 用物理触发器限定收集范围

如果磁铁有有效收集半径,给玩家添加SphereCollider(设为触发器),只处理进入范围的金币:

  • 给玩家对象添加SphereCollider,勾选Is Trigger并调整半径为磁铁有效范围。
  • 在玩家脚本中实现触发器回调维护近距金币列表:
    private List<GameObject> _nearbyCoins = new List<GameObject>();
    
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("coin"))
        {
            _nearbyCoins.Add(other.gameObject);
        }
    }
    
    void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("coin"))
        {
            _nearbyCoins.Remove(other.gameObject);
        }
    }
    
  • 之后在UseMagnet中遍历_nearbyCoins,按距离排序后执行收集。

4. 对象池优化(针对金币频繁生成场景)

如果金币是重复生成销毁的,使用对象池可以避免实例化/销毁的额外开销,同时对象池本身会维护所有金币实例(活跃/非活跃),可直接从中获取活跃金币列表。


内容的提问来源于stack exchange,提问作者user17248503

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 21:35:22