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

Unity Physics.OverlapSphere调用后是否持续存在?检测列表异常排查

问题根因

你的列表混乱和OverlapSphere API本身无关,核心bug是协程被反复无节制启动,导致检测逻辑完全失控,和你猜测的多实例冲突没有关系。

看你原代码Update里的逻辑:

  1. 首次进入Update时_runDetection为true,执行一次检测后把_runDetection设为false
  2. 从下一帧开始,只要_runDetection是false,每一帧都会启动一个新的DetectionCooldown协程
  3. 这些协程都会在启动0.1秒后把_runDetection设回true,运行时间越长,堆积的协程数量越多:运行1秒就会堆积近百个等待中的协程,这些协程会反复触发检测,甚至同一帧多次覆盖collectablesInRange列表,最终表现就是数据随时间推移越来越混乱,同时伴随性能下降。

其他隐患

你当前使用Physics.OverlapSphereNonAlloc的写法还有个不规范的地方:该API的返回值是本次检测实际命中的碰撞体数量,数组只有从索引0到返回值-1的区间是本次有效结果,数组剩余位置不会被主动清空。你现在虽然每次新建长度为20的碰撞体数组暂时不会碰到残留值问题,但如果后续为了优化GC把数组改成类成员复用,直接遍历整个数组判空会把上一次检测的残留碰撞体也算入结果,同样会导致列表数据错误。


修复方案

最简洁的实现是去掉Update里的状态判断,直接用一个常驻协程按固定间隔跑检测,从根源避免重复启动协程的问题,同时规范NonAlloc的结果读取逻辑:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Inventory
{
    public class PickUpRadius : MonoBehaviour
    {
        [SerializeField] private float detectionRadius;
        [SerializeField] private float detectionInterval = 0.1f;
        [SerializeField] private List<Collectable> collectablesInRange = new ();
        // 复用碰撞体数组,避免每次检测产生GC
        private Collider[] _hitBuffer = new Collider[20];

        private void Awake()
        {
            StartCoroutine(ContinuousDetection());
        }

        private IEnumerator ContinuousDetection()
        {
            while (true)
            {
                DetectCollectables();
                yield return new WaitForSeconds(detectionInterval);
            }
        }

        private void DetectCollectables()
        {
            collectablesInRange.Clear();
            // 只读取本次实际命中的碰撞体
            int hitCount = Physics.OverlapSphereNonAlloc(transform.position, detectionRadius, _hitBuffer, LayerMask.GetMask("Collectable"));
            for (int i = 0; i < hitCount; i++)
            {
                if (_hitBuffer[i].TryGetComponent(out Collectable collectable))
                {
                    collectablesInRange.Add(collectable);
                }
            }
        }

        private void OnDrawGizmosSelected()
        {
            Gizmos.color = new Color32(100, 255, 100, 100);
            Gizmos.DrawWireSphere(transform.position, detectionRadius);
        }
    }
}

补充说明

如果你还是想用触发器方案实现也可以,但当前OverlapSphere方案本身是可行的,修复协程逻辑后就能正常运行。如果场景中可收集物数量可能超过20,记得把_hitBuffer的长度调大,或者在检测到hitCount等于数组长度时自动扩容数组,避免漏检。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:27:23