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

如何获取半径范围内及范围外的Collider列表以优化游戏?

实现半径范围内/外的Collider分组获取

核心思路

先确定需要检测的目标Collider集合,再通过距离判断或物理查询将Collider分为「半径内」和「半径外」两个列表,同时兼顾性能优化减少不必要的计算和GC开销。

实现方案(Unity C#)

方案一:先查范围内,再补范围外

利用Unity物理引擎的OverlapSphereNonAlloc快速获取半径内的Collider,再从总列表中排除这些Collider得到范围外的集合,适合目标Collider数量较多的场景:

using UnityEngine;
using System.Collections.Generic;

public class ColliderRangeHandler : MonoBehaviour
{
    public float detectionRadius = 6f;
    public LayerMask targetLayers; // 指定要检测的层

    private List<Collider> _allTargetColliders = new List<Collider>();
    private List<Collider> _inRangeColliders = new List<Collider>();
    private List<Collider> _outOfRangeColliders = new List<Collider>();

    private void Awake()
    {
        // 初始化时一次性获取目标层的所有Collider,避免重复查找
        Collider[] tempColliders = FindObjectsOfType<Collider>();
        foreach (Collider col in tempColliders)
        {
            if (((1 << col.gameObject.layer) & targetLayers) != 0)
            {
                _allTargetColliders.Add(col);
            }
        }
    }

    // 调用此方法执行拆分
    public void SplitCollidersByRange()
    {
        _inRangeColliders.Clear();
        _outOfRangeColliders.Clear();

        // 用非Alloc版本减少GC分配,提前创建足够大的数组
        Collider[] tempInRange = new Collider[_allTargetColliders.Count];
        int inRangeCount = Physics.OverlapSphereNonAlloc(transform.position, detectionRadius, tempInRange, targetLayers);

        // 填充范围内列表
        for (int i = 0; i < inRangeCount; i++)
        {
            _inRangeColliders.Add(tempInRange[i]);
        }

        // 从总列表中筛选出范围外的Collider
        foreach (Collider col in _allTargetColliders)
        {
            if (!_inRangeColliders.Contains(col))
            {
                _outOfRangeColliders.Add(col);
            }
        }
    }
}

方案二:直接遍历判断距离

通过计算Collider到中心点的距离平方(避免开根号运算)来分组,适合目标Collider数量较少的场景,逻辑更直观:

public void SplitCollidersByDistance()
{
    _inRangeColliders.Clear();
    _outOfRangeColliders.Clear();

    Vector3 centerPos = transform.position;
    float radiusSquared = detectionRadius * detectionRadius; // 预计算半径平方,减少重复计算

    foreach (Collider col in _allTargetColliders)
    {
        float distanceSquared = (col.transform.position - centerPos).sqrMagnitude;
        if (distanceSquared <= radiusSquared)
        {
            _inRangeColliders.Add(col);
        }
        else
        {
            _outOfRangeColliders.Add(col);
        }
    }
}

性能优化要点

  • 缓存目标Collider列表:仅在初始化或场景有动态Collider生成时更新列表,不要每帧调用FindObjectsOfType。
  • 使用距离平方比较:避免Mathf.Sqrt的计算开销,直接比较距离平方和半径平方。
  • 优先用非Alloc物理接口:比如OverlapSphereNonAlloc、OverlapBoxNonAlloc,减少GC分配,适合高频调用场景。
  • 精准过滤Layer:通过LayerMask只检测需要的层,减少需要处理的Collider数量。
  • 按需调用拆分方法:不要每帧都执行拆分,仅在中心点移动、半径变化或必要时触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 23:20:38