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

Unity中Physics.OverlapSphere系列接口无法稳定检测Player的问题求助

Unity中Physics.OverlapSphere系列接口无法稳定检测Player的问题求助

我最近碰到个头疼的Unity Bug:当操控Player反复进出Enemy的sightRadius范围几次后,Enemy就再也没法正确检测到Player了——哪怕Player明明在检测范围内,Enemy也不会去追,只有重启游戏才能恢复正常。这个问题在Unity 2020和2022版本里都能复现。

问题具体表现

  • 正常状态下:Player在Enemy的sightRadius范围内时,FoundPlayer()方法里的numColliders会打印3;Player在范围外时,打印2。
  • 异常状态下:多次进出范围后,就算Player回到Enemy的检测范围内,numColliders只会打印2,Enemy不再识别Player,也不会触发追踪逻辑。

核心检测代码

这是负责检测Player的关键方法:

bool FoundPlayer()
{
    int numColliders = Physics.OverlapSphereNonAlloc(transform.position, sightRadius, colliders);
    Debug.Log(numColliders);
    for (int i = 0; i < numColliders; i++)
    {
        var target = colliders[i];
        if (target.CompareTag("Player"))
        {
            attackTarget = target.gameObject;
            return true;
        }
    }
    attackTarget = null;
    return false;
}

Enemy完整代码

using UnityEngine;
using UnityEngine.AI;


enum EnemyStatus 
{   
    GURAD, 
    PATROL, 
    CHASE, DEAD 
}

[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(BoxCollider))]
public class EnemyController : MonoBehaviour
{
    private EnemyStatus enemyStates;
    private NavMeshAgent agent;
    private Animator animator;

    [Header("Basic Settings")]
    public float sightRadius;
    private GameObject attackTarget;
    // 单次检测最多获取10个碰撞体
    const int maxColliders = 10;
    private Collider[] colliders = new Collider[maxColliders];

    // 基础移动速度,巡逻/追踪状态会调整
    private float speed;
    // 是否为守卫模式(无目标时原地警戒)
    public bool isGuard;


    [Header("Patrol State")]
    public float patrolRange;
    private Vector3 wayPoint;
    private Vector3 centerPosition;

    // 动画控制参数
    bool isWalk;
    bool isChase;
    bool isFollow;

    private void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
        animator =  GetComponent<Animator>();
        speed = agent.speed;
        wayPoint = centerPosition = transform.position;
    }

    private void Start()
    {
        enemyStates = isGuard ? EnemyStatus.GURAD : EnemyStatus.PATROL;
    }
    private void Update()
    {
        SwitchStates();
        SwitchAnimation();
    }

    void SwitchAnimation()
    {
        animator.SetBool("Walk", isWalk);
        animator.SetBool("ChaseState", isChase);
        animator.SetBool("Follow", isFollow);
    }

    private void SwitchStates()
    {
        if (FoundPlayer())
        {
            enemyStates = EnemyStatus.CHASE;
        }
        switch(enemyStates)
        {
            case EnemyStatus.GURAD:
                break;
            case EnemyStatus.PATROL:
                isChase = false;
                isFollow = false;

                if (Vector3.Distance(transform.position, wayPoint) <= agent.stoppingDistance )
                {
                    wayPoint = GetNewWayPoint();
                    agent.destination = wayPoint;
                    agent.speed = speed * 0.5f;
                    isWalk = false;
                }
                else
                {
                    isWalk = true;
                }
                break;
            case EnemyStatus.CHASE:
                isWalk = false;
                isChase = true;
                if (FoundPlayer())
                {
                    agent.destination = attackTarget.transform.position;
                    agent.speed = speed;
                    isFollow = true;
                } 
                else
                {
                    isFollow = false;
                    agent.destination = transform.position;
                }
                break;
            case EnemyStatus.DEAD:
                break;
        }
    }

    bool FoundPlayer()
    {
        int numColliders = Physics.OverlapSphereNonAlloc(transform.position, sightRadius, colliders);
        Debug.Log(numColliders);
        for (int i = 0; i < numColliders; i++)
        {
            var target = colliders[i];
            if (target.CompareTag("Player"))
            {
                attackTarget = target.gameObject;
                return true;
            }
        }
        attackTarget = null;
        return false;
    }

    Vector3 GetNewWayPoint ()
    {
        Vector3 wayPoint = new Vector3(centerPosition.x + Random.Range(-patrolRange, patrolRange), centerPosition.y, centerPosition.z + Random.Range(-patrolRange, patrolRange));
        NavMeshHit hit;
        // 采样最近的可导航点,避免巡逻点无法到达
        wayPoint = NavMesh.SamplePosition(wayPoint, out hit, patrolRange, 1) ? hit.position : transform.position;
        return wayPoint;
    }
    private void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.blue;
        Gizmos.DrawWireSphere(transform.position, sightRadius);
        Vector3 size = new Vector3(patrolRange, patrolRange, patrolRange);
        Gizmos.DrawWireCube(centerPosition, size);
    }
}

相关组件配置

  • Player组件:挂载Capsule Collider、Rigidbody,Tag设置为Player,Layer为Default。
  • Plane组件:挂载Mesh Collider,Layer为Default,作为地面使用。

排查到的线索

我试过把OverlapSphereNonAlloc换成OverlapSphere接口,结果问题依然存在。后来偶然发现:只要开启Player的Rigidbody组件上的Use gravity选项,就会触发这个问题;而且Player的transform位置显示正常(站在Plane上),但Rigidbody面板里的Position的y值一直在持续减小,像是在不断往下掉一样。

备注:内容来源于stack exchange,提问作者undefined

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 12:43:06