Unity Physics.OverlapSphere调用后是否持续存在?检测列表异常排查
问题根因
你的列表混乱和OverlapSphere API本身无关,核心bug是协程被反复无节制启动,导致检测逻辑完全失控,和你猜测的多实例冲突没有关系。
看你原代码Update里的逻辑:
- 首次进入
Update时_runDetection为true,执行一次检测后把_runDetection设为false - 从下一帧开始,只要
_runDetection是false,每一帧都会启动一个新的DetectionCooldown协程 - 这些协程都会在启动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
相关产品推荐
相关产品推荐

