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

Unity中如何通过引用向队列添加Waypoint且避免意外修改?

解决Waypoint引用队列重复问题的几种方案

首先得明确核心问题:因为Waypoint是继承自MonoBehaviour的引用类型,正常情况下你把CurrentWaypoint指向的实例存入队列后,后续修改CurrentWaypoint指向新节点时,队列里的旧引用应该还是指向原来的实例——除非你的代码逻辑里每次入队的都是同一个实例引用。针对你遇到的队列全是同一引用的问题,咱们可以用下面几种方法来规避:

1. 存储Waypoint的唯一标识符而非实例引用

给每个Waypoint类添加一个唯一ID字段,直接用Unity自带的实例ID就很方便,每个MonoBehaviour实例的ID都是全局唯一的:

public class Waypoint : MonoBehaviour
{
    // 直接用Unity生成的实例ID作为唯一标识
    public int UniqueId => GetInstanceID();
}

然后把队列改成存储int类型的ID:

Queue<int> visitedWaypointIds = new Queue<int>();

// AI抵达当前Waypoint时,将ID加入队列
visitedWaypointIds.Enqueue(currentWaypoint.UniqueId);

// 检查下一个节点是否已访问过
if (!visitedWaypointIds.Contains(nextWaypoint.UniqueId))
{
    currentWaypoint = nextWaypoint;
}

这种方法完全避开了引用类型的坑,因为存的是值类型的ID,不会出现引用被意外修改的情况,检查效率也很高。

2. 修正代码逻辑,确保入队的是当前实例引用

如果你还是想直接存Waypoint实例,那要确保每次入队的是当前指向的具体实例,而不是后续会被重新赋值的变量本身。正确的代码逻辑应该是这样:

Queue<Waypoint> visitedWaypoints = new Queue<Waypoint>();
Waypoint currentWaypoint;

// 第一步:先把当前抵达的Waypoint实例加入队列
visitedWaypoints.Enqueue(currentWaypoint);

// 第二步:再修改currentWaypoint指向新的下一个节点
currentWaypoint = GetNextTargetWaypoint();

这样队列里存入的是旧节点的实例引用,后续修改currentWaypoint指向新节点时,队列里的旧引用不会受到任何影响。如果你的队列还是全是同一引用,那大概率是GetNextTargetWaypoint()方法有问题,每次都返回同一个实例,这时候就要检查寻路逻辑了。

3. 用HashSet代替队列(仅需去重检查时更高效)

如果你的需求只是防止AI返回已访问过的节点,不需要记录访问顺序,那用HashSet<Waypoint>会比队列高效得多——它的Contains方法是O(1)时间复杂度,而队列是O(n):

HashSet<Waypoint> visitedWaypoints = new HashSet<Waypoint>();

// 抵达节点时添加到集合
visitedWaypoints.Add(currentWaypoint);

// 检查下一个节点是否已访问
if (!visitedWaypoints.Contains(nextWaypoint))
{
    currentWaypoint = nextWaypoint;
}

HashSet会自动过滤重复的实例引用,同一个Waypoint只能被添加一次,完美解决重复问题。

额外注意事项

  • 如果直接存实例引用,要注意Waypoint对象被销毁的情况(比如场景切换),检查时先判断waypoint != null,避免空引用错误。
  • 若需要记录访问顺序但又要去重,也可以用Queue搭配HashSet,用HashSet做快速检查,用Queue记录顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:54:22