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

Unity实现汽车转向行为seek算法时wayIndex不更新车辆卡首路点问题

问题根因与修正方案

核心故障点

  • 路点到达判断逻辑错误:使用Vector3绝对相等判断不符合浮点运算特性,车辆实际位移几乎不可能完全匹配路点坐标,是wayIndex无法更新、车辆卡在第一个路点的核心原因
  • Seek算法实现无效:自定义seek方法中vel和desiredVel计算逻辑完全一致,返回的转向力恒为零,同时持续累加steering变量会导致速度异常漂移
  • 逻辑执行顺序存在越界风险:先自增wayIndex再判断是否到达最后一个路点,会触发数组下标越界报错
  • 初始位置设置矛盾:Start方法直接将车辆初始位置设置为第一个路点坐标,后续位移逻辑反而会让车辆偏离起始路点,错过触发索引更新的时机

修正后完整代码

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

public class Follower : MonoBehaviour
{
    public GameObject vehicle;
    public float[] speeds = {15.0f,25.0f,35.0f};
    public int pathChoice;
    // 路点到达判定阈值,可根据实际需求调整
    public float reachThreshold = 1f;

    [SerializeField]
    public Transform[] waypoints;
    public Transform[] waypoints2;

    [SerializeField]
    public float speed;
    private int wayIndex = 0;

    private Vector3 target;
    private Vector3 currentVelocity;
    // 最大转向力,控制转向灵敏度
    public float maxSteerForce = 5f;

    private void Start(){
        int speedIndex = UnityEngine.Random.Range(0, 3);
        int pathIndex = UnityEngine.Random.Range(0, 2);
        speed = speeds[speedIndex];
        pathChoice = pathIndex;
        currentVelocity = Vector3.zero;

        if (pathIndex == 0){
            target = waypoints[wayIndex].position;
            // 初始位置可改为路点组的起始前位置,避免初始就重合
            // transform.position = waypoints[wayIndex].transform.position;
        }else if (pathIndex == 1){
            target = waypoints2[wayIndex].position;
            // transform.position = waypoints2[wayIndex].transform.position;
        }
    }

    private void Update(){
        MoveVehicle();
    }

    private void MoveVehicle(){
        Transform[] activePath = pathChoice == 0 ? waypoints : waypoints2;
        if (wayIndex >= activePath.Length) return;

        target = activePath[wayIndex].position;
        transform.LookAt(target);

        if (pathChoice == 0)
        {
            // 修正后的Seek逻辑
            Vector3 desiredVel = (target - transform.position).normalized * speed;
            Vector3 steerForce = Vector3.ClampMagnitude(desiredVel - currentVelocity, maxSteerForce);
            currentVelocity = Vector3.ClampMagnitude(currentVelocity + steerForce * Time.deltaTime, speed);
            transform.position += currentVelocity * Time.deltaTime;
        }
        else
        {
            transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
        }

        // 用距离判断是否到达路点,兼容两种位移逻辑
        if (Vector3.Distance(transform.position, target) < reachThreshold)
        {
            wayIndex++;
            // 到达最后一个路点的处理逻辑
            if (wayIndex >= activePath.Length)
            {
                speed = 0f;
                if (pathChoice == 1)
                {
                    vehicle.GetComponent<Follower>().enabled = false;
                    if(vehicle.TryGetComponent(out Collisions col)) col.enabled = false;
                    Destroy(vehicle);
                }
            }
        }
    }
}

关键修改说明

  1. 把路点到达判断从绝对相等改为距离阈值判断,避免浮点误差导致的触发失败
  2. 重写了Seek算法逻辑,增加了速度累积和转向力限制,保证转向效果正常
  3. 调整了逻辑执行顺序,先判断是否到达路点再更新索引,最后统一处理路径结束逻辑,避免数组越界
  4. 注释掉了初始位置设置为第一个路点的逻辑,避免初始状态就触发索引更新
  5. 复用了路径判断逻辑,减少重复代码,同时增加了组件获取的安全校验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 10:24:07