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

Unity跨脚本传递Vector3列表后,对象完成首段路径后停止移动

问题分析与解决方案

核心问题

问题出在StartMoving和NextStep的交互逻辑上:
当完成第一段路径调用NextStep()时,会执行StartMoving(pathRover)。此时StartMoving第一行就是pathRover.Clear(),直接清空了当前剩余的路径点;之后尝试从已清空的pathReceived(也就是pathRover本身)中添加元素,自然得不到任何内容,最终pathRover.Count变为0,触发StopMoving()导致机器人停止。

修复方案

方案1:重构路径推进逻辑(推荐)

直接移除已完成的路径点,避免重复调用StartMoving时清空列表:

public List<Vector3> pathRover;
[SerializeField] private float roverSpeed;
[SerializeField] private float roverRotateSpeed;
private float dotto;
private bool isRotating = false;
private bool isLerping = false;
private Vector3 startPosition;
private Vector3 targetPosition;

private void FixedUpdate()
{
    if (isRotating)
    {
        dotto = Vector3.Dot(transform.TransformDirection(Vector3.forward), 
                           (new Vector3(targetPosition.x, 0, targetPosition.z) - new Vector3(startPosition.x, 0, startPosition.z)).normalized);

        if (dotto < 0.98f)
        {
            transform.Rotate(0, Time.deltaTime * roverRotateSpeed, 0);
        }
        else
        {
            isLerping = true;
            isRotating = false;
        }
    }
    else if (isLerping)
    {
        var step = roverSpeed * Time.deltaTime;
        transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
        
        if (Vector3.Distance(transform.position, targetPosition) <= 1f)
        {
            NextStep();
        }
    }
}

public void StartMoving(List<Vector3> pathReceived)
{
    if (pathReceived.Count == 0)
    {
        StopMoving();
        return;
    }
    
    pathRover.Clear();
    foreach (var point in pathReceived)
    {
        pathRover.Add(point);
    }
    SetNextTarget();
}

// 单独处理目标点设置逻辑
private void SetNextTarget()
{
    if (pathRover.Count == 0)
    {
        StopMoving();
        return;
    }
    
    startPosition = transform.position;
    var targetPoint = pathRover[0];
    targetPosition = new Vector3(targetPoint.x, targetPoint.y + 0.7f, targetPoint.z);
    isRotating = true;
}

public void StopMoving()
{
    isRotating = false;
    isLerping = false;
    pathRover.Clear();
}

public void NextStep()
{
    isLerping = false;
    // 移除已到达的路径点
    pathRover.RemoveAt(0);
    SetNextTarget();
}

方案2:区分外部/内部调用(最小改动)

给StartMoving添加参数标记,避免内部调用时清空列表:

public void StartMoving(List<Vector3> pathReceived, bool isInternalCall = false)
{
    if (pathReceived.Count <= 0)
    {
        StopMoving();
        return;
    }
    
    // 仅外部传入路径时清空并复制
    if (!isInternalCall)
    {
        pathRover.Clear();
        foreach (var point in pathReceived)
        {
            pathRover.Add(point);
        }
    }
    
    if (pathRover.Count > 0)
    {
        startPosition = transform.position;
        targetPosition = new Vector3(pathRover[0].x, pathRover[0].y + 0.7f, pathRover[0].z);
        isRotating = true;
    }
    else
    {
        StopMoving();
    }
}

public void NextStep()
{
    isLerping = false;
    pathRover.RemoveAt(0);
    // 内部调用,跳过清空逻辑
    StartMoving(pathRover, true);
}

额外优化点

  • 原代码中pathReceived.Count > 1的判断不合理,应该允许路径只有一个点(直接移动到目标)
  • 可以将Vector3.Distance的判断阈值改为更小的值(比如0.1f),避免因阈值过大导致提前触发下一步

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 05:24:09