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

Unity中首路径节点销毁后Agent无法更新移动目标的问题

问题根因
  • 每帧调用FindGameObjectsWithTag获取的对象数组,Unity不保证返回顺序和你预期的路径顺序一致,不会自动实现「第一个节点销毁后下一个自动顶到索引0」的效果,甚至可能返回已经销毁但未被引擎回收的空对象。
  • 已经挂载NavMeshAgent组件但完全没有调用其导航接口,自行编写的MoveTowards混合Lerp移动逻辑存在缺陷,写的for循环全程只读取trailLists[0],循环无实际作用,也没有添加「是否到达当前目标」的判定逻辑,Agent抵达首个点后自然卡住。
  • 未做空引用过滤:路径节点销毁后列表中会存储null值,此时访问trailLists[0].transform会直接抛出空引用异常,后续逻辑全部中断,Agent不会再响应移动指令。
修复方案

核心逻辑调整:初始加载一次路径节点列表,每帧仅清理列表中已销毁的空节点,始终将列表首位节点作为当前移动目标,正确调用NavMeshAgent接口完成导航,节点销毁后会被自动移出列表,下一个节点自动成为新的首位目标,无需手动维护索引。
修复后完整代码:

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

public class MoveToTrail : MonoBehaviour
{
    [Header("路径配置")]
    [SerializeField] private string trailTag = "Trail";
    [SerializeField] private float reachThreshold = 0.3f; // 到达目标的判定距离
    [SerializeField] private float moveSpeed = 5f;

    private List<GameObject> trailList = new List<GameObject>();
    private NavMeshAgent navMeshAgent;

    private void Awake()
    {
        navMeshAgent = GetComponent<NavMeshAgent>();
        navMeshAgent.speed = moveSpeed;
        // 初始加载所有路径节点
        RefreshTrailList();
    }

    private void Update()
    {
        // 清理列表中已销毁的空节点
        CleanDestroyedTrail();
        // 无剩余路径则停止移动
        if (trailList.Count == 0)
        {
            navMeshAgent.isStopped = true;
            return;
        }
        // 取首位节点为当前目标
        GameObject currentTarget = trailList[0];
        // 未到达目标则持续导航
        if (Vector3.Distance(transform.position, currentTarget.transform.position) > reachThreshold)
        {
            navMeshAgent.isStopped = false;
            navMeshAgent.SetDestination(currentTarget.transform.position);
        }
    }

    // 刷新路径节点列表
    private void RefreshTrailList()
    {
        trailList = GameObject.FindGameObjectsWithTag(trailTag)
            .Where(go => go != null)
            .ToList();
        // 若返回的节点顺序和预期路径不一致,在此处添加自定义排序逻辑,例如按坐标、节点命名序号排序
    }

    // 移除列表中已销毁的节点
    private void CleanDestroyedTrail()
    {
        for (int i = trailList.Count - 1; i >= 0; i--)
        {
            if (trailList[i] == null)
            {
                trailList.RemoveAt(i);
            }
        }
    }
}
关键修改点
  • 移除无意义的每帧全量节点查找和无效for循环,仅在初始时加载一次路径列表,每帧只做已销毁节点清理,性能开销更低。
  • 正确调用NavMeshAgent.SetDestination实现导航,无需自行编写位置插值逻辑,引擎自动处理寻路、避障、移动平滑度。
  • 新增到达距离判定,当前首位节点未销毁、Agent未抵达目标点时持续向该点移动;节点销毁后会被自动移出列表,下一个节点自动成为新目标,无需手动切换索引。
  • 新增空引用防护,避免访问已销毁对象的组件导致脚本异常中断。

注意:如果FindGameObjectsWithTag返回的节点顺序和你设计的路径走向不符,必须在RefreshTrailList方法中添加自定义排序规则,比如按路径节点的坐标排序、按节点名称的数字序号排序,确保列表顺序和路径顺序完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:39:18