Unity AI巡逻状态异常:仅移动至单个Waypoint后停止
Unity AI巡逻与追击功能修复方案
问题根源分析
- 初始巡逻未启动:Start()中仅标记了巡逻状态,但未主动设置第一个Waypoint目标,导致
agent.remainingDistance始终大于阈值,无法触发第一次巡逻逻辑。 - Waypoint切换逻辑错误:原代码用
Random.Range随机选点,不符合“循环遍历指定Waypoint”的需求,且无法形成连续巡逻路径。 - 追击状态目标更新失效:追击时timer初始值为0,导致无法定期更新Player位置,追踪逻辑形同虚设。
- 动画速度处理冲突:非追击状态下的强制减速逻辑会将动画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
相关产品推荐
相关产品推荐

