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

Unity中如何避免被射击的Target对象与其他Target重叠

解决Target随机位置重叠的几种实用方案

1. 实时碰撞检测法(最直接)

每次生成新位置后,立刻检查该位置是否与其他Target的碰撞体重叠,直到找到一个安全位置为止。注意先修正你代码里Y轴随机范围的小问题——Random.Range(min, max)要求最小值小于等于最大值,原代码里3.2f到-3.95f会生成错误的随机数。

public void Shoot()
{
    Ray gunRay = new Ray(camera.position, camera.forward);
    if(Physics.Raycast(gunRay, out RaycastHit hit, bulletRange))
    {
        if(hit.collider.gameObject.TryGetComponent(out Target target))
        {
            // 根据你的Target碰撞体大小调整检测半径
            float checkRadius = 1f;
            Vector3 newPos;
            bool isOverlap;
            
            do
            {
                // 生成合法范围内的随机位置
                newPos = new Vector3(Random.Range(-6.2f, 6.25f), Random.Range(-3.95f, 3.2f), 0f);
                // 检测该位置周围是否有其他Target
                Collider[] hitColliders = Physics.OverlapSphere(newPos, checkRadius);
                isOverlap = false;
                
                foreach(var col in hitColliders)
                {
                    // 排除当前Target,只检查其他同类对象
                    if(col.gameObject != target.gameObject && col.TryGetComponent(out Target _))
                    {
                        isOverlap = true;
                        break;
                    }
                }
            } while(isOverlap);
            
            target.transform.position = newPos;
        }
    }
}

2. 预生成位置池法(性能更稳定)

提前在合法区域内生成一批不重叠的位置存入列表,每次刷新Target位置时直接从池子里随机选取未被占用的位置,避免实时检测的性能消耗。

// 存储所有预生成的合法位置
private List<Vector3> positionPool = new List<Vector3>();
// 记录当前被占用的位置
private HashSet<Vector3> usedPositions = new HashSet<Vector3>();
// 位置间距,确保生成的位置不会重叠
public float positionSpacing = 2f;

void Start()
{
    GeneratePositionPool();
}

void GeneratePositionPool()
{
    // 按网格遍历生成所有不重叠的位置
    for(float x = -6.2f; x <= 6.25f; x += positionSpacing)
    {
        for(float y = -3.95f; y <= 3.2f; y += positionSpacing)
        {
            positionPool.Add(new Vector3(x, y, 0f));
        }
    }
}

public void Shoot()
{
    Ray gunRay = new Ray(camera.position, camera.forward);
    if(Physics.Raycast(gunRay, out RaycastHit hit, bulletRange))
    {
        if(hit.collider.gameObject.TryGetComponent(out Target target))
        {
            // 释放当前Target的位置回池
            usedPositions.Remove(target.transform.position);
            
            // 随机选一个未被占用的位置
            Vector3 newPos;
            do
            {
                newPos = positionPool[Random.Range(0, positionPool.Count)];
            } while(usedPositions.Contains(newPos));
            
            usedPositions.Add(newPos);
            target.transform.position = newPos;
        }
    }
}

3. 物理排斥法(快速实现)

给每个Target添加刚体组件,利用Unity物理引擎自动处理重叠问题。这种方式可控性稍弱,但实现最简单。

public void Shoot()
{
    Ray gunRay = new Ray(camera.position, camera.forward);
    if(Physics.Raycast(gunRay, out RaycastHit hit, bulletRange))
    {
        if(hit.collider.gameObject.TryGetComponent(out Target target))
        {
            Rigidbody rb = target.GetComponent<Rigidbody>();
            if(rb == null) rb = target.gameObject.AddComponent<Rigidbody>();
            
            // 生成随机位置
            target.transform.position = new Vector3(Random.Range(-6.2f, 6.25f), Random.Range(-3.95f, 3.2f), 0f);
            
            // 临时关闭Kinematic,让物理引擎自动推开重叠的对象
            rb.isKinematic = false;
            // 下一帧重新开启,避免Target受物理影响移动
            StartCoroutine(EnableKinematicAfterFrame(rb));
        }
    }
}

IEnumerator EnableKinematicAfterFrame(Rigidbody rb)
{
    yield return null;
    rb.isKinematic = true;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:46:19