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

Unity AI巡逻与NavMesh追击切换else分支不生效问题排查

Unity AI巡逻/追击状态切换异常排查

问题背景

  • 已实现基础点位巡逻逻辑:通过Transform数组存储所有巡逻点位,AI按顺序逐点移动,遍历完成后回到首个点位循环巡逻。
  • 预期实现射线检测触发的状态切换:射线检测到敌人时,停止巡逻逻辑、启用NavMeshAgent进入追击状态;未检测到敌人时,关闭NavMeshAgent、启用巡逻逻辑回到巡逻状态。实际运行时未检测到敌人的分支始终无法正常触发。

现有实现代码

巡逻脚本代码

public Transform[] Points;
public int current;

public NavMeshAgent agent;

public milkscript milk;
public float speed;

// Start is called before the first frame update
void Start()
{
    current = 0;
    agent.enabled = false;
}

// Update is called once per frame
void Update()
{
    if(milk.chasing == false) 
    {
        agent.enabled = false;
        Patol();
    }
    if(milk.chasing == true) 
    {
        agent.enabled = true;
    }
}

public void Patol() 
{
    if(transform.position != Points[current].position) 
    {
        transform.position = Vector3.MoveTowards(transform.position,Points[current].position, speed * Time.deltaTime);
    }
    else 
    {
        // 此处运算优先级错误,会导致索引无法正常循环
        current = current+1 % Points.Length;
    }

    // 硬编码重置索引,巡逻点数量不为8时会数组越界
    if(current == 8) 
    {
        current = 0;
    }
}

射线检测/追击脚本代码

NavMeshAgent Agent;
public Patrol patrol;
public bool chasing;
public Transform enemy;
public Transform[] Points;
[SerializeField] LayerMask layermask;
public Transform Point;
public float raydistance = 10f;
public float enemyview = 5f;

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

// Update is called once per frame
void Update()
{
    if(Physics.Raycast(Point.position, Point.forward, out var Hit, raydistance, layermask)) 
    {
        Debug.DrawLine(Point.position, Hit.transform.position, Color.red);
        Debug.Log(Hit.transform.name);
        
        if(Hit.transform.name == "Chocltaemilk") 
        {
            chasing = true;
            // 此处逻辑和后续状态判断冲突
            patrol.enabled = true;
            Agent.SetDestination(Hit.transform.position);
        }
        // 缺少关键逻辑:射线检测到其他非目标物体时,没有重置chasing状态
    }
    else 
    {
        Agent.enabled = false;
        Debug.DrawRay(Point.position, Point.forward, Color.green);
        patrol.Patol();
    }

    if(chasing == false) 
    {   
        Agent.enabled = false;
        patrol.enabled = true;
    }
     
    if(chasing == true) 
    {   
        Agent.enabled = true;
        patrol.enabled = false;
    }
}

void returen() 
{
    chasing = false;
    patrol.enabled = false;
}

public void ChasePlayer(Transform target)
{
    Agent.SetDestination(target.position);
    transform.LookAt(target.position);
}

核心问题点与修复方案

  1. 追击状态无法正常退出是核心bug
    射线检测逻辑只在「检测到的物体刚好是目标敌人」时把chasing设为true,但只要射线扫到了分层里的其他物体(地面、墙、场景道具),Physics.Raycast就会返回true进入if分支,此时因为物体名不匹配,不会修改chasing的值,导致chasing一旦设为true就再也没机会被改回false,else分支自然永远不会正常执行。
    修复方式:在射线检测到非目标物体时,增加chasing = false的状态重置;也可以加个丢失目标计时,连续N帧没检测到敌人再切回巡逻,避免状态反复横跳。

  2. 巡逻点索引计算逻辑错误
    代码里current = current+1 % Points.Length;存在运算符优先级问题,取模%优先级高于加法+,实际执行逻辑是current = current + (1 % Points.Length),索引只会一直累加不会循环,后面硬编码current == 8重置的写法通用性极差,只要巡逻点数量不是8就会触发数组越界。
    修复方式:改成current = (current + 1) % Points.Length;,直接删掉后面判断current等于8重置的冗余代码。

  3. 双脚本重复控制状态,逻辑互相覆盖
    巡逻脚本和追击脚本都在Update里反复开关NavMeshAgent、反复控制巡逻脚本的启用状态,两边逻辑不同步很容易出现状态被覆盖的问题。比如追击脚本else分支刚调用完巡逻方法,后面紧接着的if(chasing == true)又会把巡逻脚本关掉,等于前面的逻辑白执行。
    修复方式:把状态切换的逻辑统一收敛到一个脚本里,不要两个脚本同时修改组件启用状态和AI行为。

  4. 追击逻辑不完整
    目前只有第一次检测到敌人时会调用一次SetDestination,敌人移动时NavMeshAgent不会实时更新追击目标点,会出现追着空气跑的问题。修复方式是在追击状态下每帧调用SetDestination更新目标位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:01:06