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

Unity AI巡逻状态异常:仅移动至单个Waypoint后停止

Unity AI巡逻与追击功能修复方案

问题根源分析

  1. 初始巡逻未启动:Start()中仅标记了巡逻状态,但未主动设置第一个Waypoint目标,导致agent.remainingDistance始终大于阈值,无法触发第一次巡逻逻辑。
  2. Waypoint切换逻辑错误:原代码用Random.Range随机选点,不符合“循环遍历指定Waypoint”的需求,且无法形成连续巡逻路径。
  3. 追击状态目标更新失效:追击时timer初始值为0,导致无法定期更新Player位置,追踪逻辑形同虚设。
  4. 动画速度处理冲突:非追击状态下的强制减速逻辑会将动画Speed清零,可能导致后续巡逻时动画无法正常启动。

修复步骤与代码实现

1. 初始化第一个巡逻目标

在Start()末尾调用GotoNextPoint(),让AI启动时立刻进入巡逻状态。

2. 改为顺序循环的Waypoint切换逻辑

将GotoNextPoint()中的随机选点改为顺序循环:

destPoint = (destPoint + 1) % points.Length;

3. 修复追击状态的目标更新逻辑

在OnTriggerEnter中重置timer,确保追击时能定期更新Player位置:

timer = maxTime;

4. 简化动画速度处理

统一使用agent.velocity.magnitude控制动画Speed,避免减速逻辑导致的冲突。

修复后的完整代码

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

public class AILocomotion : MonoBehaviour
{
    public Transform playerTransform;
    NavMeshAgent agent;
    Animator animator;
    public float maxTime = 1.0f;
    public float maxDistance = 1.0f;
    float timer = 0.0f;
    bool moveTowards = false;
    bool followWaypoint = false;
    public Transform[] points;
    private int destPoint = 0;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
        moveTowards = false;
        followWaypoint = true;
        // 初始化第一个巡逻目标
        GotoNextPoint();
    }

    void Update()
    {
        if (moveTowards)
        {
            timer -= Time.deltaTime;
            if (timer < 0.0f)
            {
                float sqDistance = (playerTransform.position - agent.destination).sqrMagnitude;
                if (sqDistance > maxDistance * maxDistance)
                {
                    agent.destination = playerTransform.position;
                }
                // 重置timer,持续追踪Player位置
                timer = maxTime;
            }
            animator.SetFloat("Speed", agent.velocity.magnitude);
        }
        else if (followWaypoint)
        {
            // 巡逻状态直接使用agent速度更新动画
            animator.SetFloat("Speed", agent.velocity.magnitude);
            // 到达目标点后切换下一个Waypoint
            if (!agent.pathPending && agent.remainingDistance < 1.0f)
            {
                GotoNextPoint();
            }
        }
        else
        {
            // 非追击非巡逻状态,逐渐减速到0
            float currentSpeed = animator.GetFloat("Speed");
            currentSpeed = Mathf.MoveTowards(currentSpeed, 0, Time.deltaTime * 0.5f);
            animator.SetFloat("Speed", currentSpeed);
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            moveTowards = true;
            followWaypoint = false;
            // 重置timer,开始追踪Player
            timer = maxTime;
            // 立刻设置追击目标为Player当前位置
            agent.destination = playerTransform.position;
        }
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            moveTowards = false;
            followWaypoint = true;
            // 退出追击后立刻回到巡逻逻辑,设置下一个Waypoint
            GotoNextPoint();
        }
    }

    void GotoNextPoint()
    {
        if (points.Length == 0)
            return;

        agent.destination = points[destPoint].position;
        // 顺序循环切换下一个Waypoint
        destPoint = (destPoint + 1) % points.Length;
    }
}

额外注意事项

  • 确保所有Waypoint都位于NavMesh区域内,否则NavMeshAgent无法生成有效路径。
  • 检查AI的Trigger Collider是否勾选Is Trigger,且Player对象带有Collider和Rigidbody(否则Trigger事件不会触发)。
  • 调整maxTime和maxDistance参数,优化追击时的目标更新频率和灵敏度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 20:25:48