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

Unity中NavMeshAgent与OverlapBox实现敌人行为的异常排查

敌人AI导航与玩家检测问题排查

问题描述

在Unity中使用NavMeshAgent组件实现敌人导航,结合Physics.OverlapBox做基于物理的玩家检测开发敌人行为逻辑时,出现玩家检测与路径巡逻功能异常。手动在Inspector勾选playerisSpotted布尔值时,敌人可正常向玩家移动,推测问题出在该布尔值的自动赋值逻辑,但未定位具体错误。

问题代码

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

public class myScript : MonoBehaviour
{
    NavMeshAgent enemy;
    public Transform target; // target = player
    public Transform[] waypoints;

    // Start is called before the first frame update
    void Start()
    {
        enemy = GetComponent<NavMeshAgent>();
    }

    int index;
    public Vector3 Chasedistance;

    public bool playerisSpotted;
    public bool isOnserach;
    
    void Update()
    {
        Collider[] colliders = Physics.OverlapBox(transform.position, Chasedistance);
        foreach (Collider col in colliders)
        {
            if (col.gameObject.CompareTag("Player"))
            {
                playerisSpotted = true;
                break;
            }
        }
        Determine_Behavior();
    }

    void Determine_Behavior()
    {
        void PatrolWaypoints()
        {
            enemy.SetDestination(waypoints[index].position);
            if (Vector3.Distance(transform.position, waypoints[index].position) < 1)
            {
                index = (index + 1) % waypoints.Length;
            }
        }

        void MoveToPlayer()
        {
            enemy.SetDestination(target.position);
        }

        if (playerisSpotted)
        {
            MoveToPlayer();
        }
        else
        {
            PatrolWaypoints();
        }
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(transform.position, Chasedistance);
    }
}

问题分析

  1. playerisSpotted无重置逻辑:代码中仅将该值设为true,从未重置为false,导致敌人一旦检测到玩家后,会一直保持追踪状态,无法回到巡逻模式。
  2. Physics.OverlapBox参数不匹配:OverlapBox的第二个参数是盒子的半扩展值(中心到边缘的距离),但Gizmos.DrawWireCube使用的是全尺寸,两者参数不一致会导致检测范围与可视化范围不符。
  3. 未处理视野遮挡:OverlapBox会检测范围内所有碰撞体,包括被障碍物遮挡的玩家,不符合实际敌人“看到玩家才追踪”的逻辑。
  4. 巡逻索引未初始化:index变量默认值为0,但未显式初始化,若waypoints数组为空会直接报错。
  5. 冗余变量未使用:isOnserach变量未在代码中调用,属于冗余代码。

解决方案

1. 补充playerisSpotted重置逻辑

每次检测前先将值重置为false,确保未检测到玩家时敌人回到巡逻:

void Update()
{
    playerisSpotted = false; // 先重置为未发现状态
    Collider[] colliders = Physics.OverlapBox(transform.position, Chasedistance / 2); // 修正半扩展参数
    foreach (Collider col in colliders)
    {
        if (col.gameObject.CompareTag("Player"))
        {
            // 可选:添加射线检测判断玩家是否在视野内
            Vector3 direction = col.transform.position - transform.position;
            if (Physics.Raycast(transform.position, direction.normalized, out RaycastHit hit, direction.magnitude))
            {
                if (hit.collider.CompareTag("Player"))
                {
                    playerisSpotted = true;
                    break;
                }
            }
            // 若不需要视野判断,直接赋值:playerisSpotted = true;
            break;
        }
    }
    Determine_Behavior();
}

2. 修正检测范围与可视化的参数一致性

将OverlapBox的半扩展参数与Gizmos的全尺寸参数统一:

// 方法一:修改OverlapBox参数(推荐)
Collider[] colliders = Physics.OverlapBox(transform.position, Chasedistance / 2);

// 方法二:修改Gizmos参数
private void OnDrawGizmos()
{
    Gizmos.color = Color.red;
    Gizmos.DrawWireCube(transform.position, Chasedistance * 2);
}

3. 初始化巡逻索引与空数组判断

在Start中初始化index,并在巡逻逻辑中处理空数组情况:

void Start()
{
    enemy = GetComponent<NavMeshAgent>();
    index = 0; // 显式初始化巡逻点索引
}

void PatrolWaypoints()
{
    if (waypoints == null || waypoints.Length == 0) return; // 避免空数组报错
    enemy.SetDestination(waypoints[index].position);
    if (Vector3.Distance(transform.position, waypoints[index].position) < 1)
    {
        index = (index + 1) % waypoints.Length;
    }
}

4. 移除冗余变量

删除未使用的isOnserach变量,保持代码整洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 21:44:52