Unity 简单载具路线 Waypoint 导航

前言

在游戏开发和导航系统中,"waypoint" 是指路径中的一个特定位置或点。它通常用于定义一个物体或角色在场景中移动的目标位置或路径的一部分。通过一系列的 waypoints,可以指定复杂的移动路径和行为。以下是一些 waypoint 的具体用途:

  1. 导航和路径规划

    • Waypoints 用于定义角色或物体从一个位置移动到另一个位置的路径。
    • 例如,在游戏中,敌人可能会沿着一系列 waypoints 巡逻。
  2. 动画和过场

    • Waypoints 可用于定义相机或对象在场景中移动的路径。
    • 例如,在过场动画中,摄像机可能会沿着预定义的路径移动,以展示场景的不同部分。
  3. 人工智能(AI)行为

    • AI 角色可以使用 waypoints 来确定移动路径和行为模式。
    • 例如,AI 角色可以沿着一系列 waypoints 移动,以模拟巡逻或探索行为。
  4. 动态事件触发

    • Waypoints 可以用作触发点,当角色或物体到达某个 waypoint 时触发特定事件或行为。
    • 例如,玩家到达某个 waypoint 时,可能会触发一段对话或开始一个任务。

Unity 简单载具路线 Waypoint 导航

实现

假设我们有一辆载具,需要通过给定的数个路径点(waypoint)来进行移动和转向。

简单粗暴的一种方法是使用Animation动画系统来为载具制作做动画,但是这个方法的致命缺点是非常不灵活,一旦需要改动路径点和模型,几乎就得重新做动画。

好在,DOTween (HOTween v2) | 动画 工具 | Unity Asset Store插件的出现让脚本解决变得异常的简单快捷,这个插件能够完美解决各种各样的过场动画和事件调用:

DOTween (HOTween v2) (demigiant.com)https://dotween.demigiant.com/index.php

  1. 这里需要先事先安装一下DOTween,没什么难度,免费!

  2. 在场景中增加你的路径点,做一个父物体,然后为子物体增加多个路径点,这里每个路径点建议使用带有方向的模型或者图片,这样便于查看

  3. 为你的载具添加文末的脚本,并挂在载具上(如果你不想挂在载具上,那简单改一下代码的变量为你的期望物体上就行)。

  4. 在inspector中绑定好你需要的路径点集合的父物体(wayPointsParent变量),这里我在父物体上额外加了一个LineRender组件,用于后续连线效果:

  5. 运行程序!车子就会动起来了!调节每一个变量,让车子移动的更自然!
    每个变量都有它的意义,比如你可以规定整个路程的总时间、转一次弯需要多少时间,转弯的起始距离阈值以及每到一个waypoint的事件调用等等,并可以更具每个人的需要自行修改和拓展!

cs 复制代码
using System;
using UnityEngine;
using DG.Tweening;
using UnityEngine.Events;

/// <summary>
/// Author: Lizhenghe.Chen https://bunnychen.top/about
/// </summary>
public class CarMover : MonoBehaviour
{
    public LineRenderer wayPointsParent;
    [Header("Total move time in seconds")] public int totalMoveTime = 300;

    [Header("Rotation duration in seconds")]
    public float rotationDuration = 2;

    [Header("Distance threshold to start rotating")]
    public float rotationStartDistance = 1;

    [Header("Show line renderer")] public bool showLineRenderer = true;

    // Duration for each segment
    [SerializeField] private int moveDuration = 5;

    // Array of transforms for the car to move towards
    [SerializeField] private Transform[] waypoints;
    [SerializeField] private Transform currentWaypoint;
    [SerializeField] private int currentWaypointIndex;
    public UnityEvent onWaypointReached;
    private MaterialPropertyBlock _propBlock;
    private static readonly int BaseColor = Shader.PropertyToID("_BaseColor");
    private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor");

    private void OnValidate()
    {
        // Get the waypoints from the parent object, do not include the parent object itself
        if (wayPointsParent == null) return;
        waypoints = new Transform[wayPointsParent.transform.childCount];
        for (var i = 0; i < waypoints.Length; i++)
        {
            waypoints[i] = wayPointsParent.transform.GetChild(i);
        }

        //foreach waypoint, set the current waypoint to look at the next waypoint
        for (var i = 0; i < waypoints.Length - 1; i++)
        {
            waypoints[i].LookAt(waypoints[i + 1]);
        }

        moveDuration = totalMoveTime / waypoints.Length;
    }

    private void Start()
    {
        OnValidate();
        if (showLineRenderer) SetLineRenderer();
        SetWaypointsSequence();
        onWaypointReached.AddListener(SetPreviousWaypointColor);
    }

    private void SetWaypointsSequence()
    {
        // Create a new Sequence for movement
        var moveSequence = DOTween.Sequence();

        // Loop through the waypoints and append DOMove tweens to the moveSequence
        foreach (var waypoint in waypoints)
        {
            moveSequence.AppendCallback(() =>
            {
                currentWaypoint = waypoint;
                currentWaypointIndex = Array.IndexOf(waypoints, waypoint);
                onWaypointReached?.Invoke();
            });
            // Move to the waypoint
            moveSequence.Append(transform.DOMove(waypoint.position, moveDuration).SetEase(Ease.Linear));

            // Create a rotation tween that starts when the car is within the specified distance to the waypoint
            moveSequence.AppendCallback(() =>
            {
                // Start rotation when close to the waypoint
                if (Vector3.Distance(transform.position, waypoint.position) < rotationStartDistance)
                {
                    // make the rotation same to the waypoint's rotation
                    transform.DORotateQuaternion(waypoint.rotation, rotationDuration).SetEase(Ease.Linear);
                }
            });
        }

        // Optionally, set some other properties on the sequence
        moveSequence.SetLoops(0); // Infinite loop
        // moveSequence.SetAutoKill(false); // Prevent the sequence from being killed after completion
    }

    private void SetLineRenderer()
    {
        //set the line renderer's position count to the number of waypoints and set the positions to the waypoints' positions
        wayPointsParent.positionCount = waypoints.Length;
        for (var i = 0; i < waypoints.Length; i++)
        {
            wayPointsParent.SetPosition(i, waypoints[i].position);
        }
    }

    private void SetPreviousWaypointColor()
    {
        _propBlock ??= new MaterialPropertyBlock();

        if (currentWaypointIndex == 0) return;
        // Set the color of the current waypoint to green, and the next waypoint to red
        waypoints[currentWaypointIndex - 1].GetComponent<MeshRenderer>().GetPropertyBlock(_propBlock);
        _propBlock.SetColor(BaseColor, Color.green);
        _propBlock.SetColor(EmissionColor, Color.green);
        waypoints[currentWaypointIndex - 1].GetComponent<MeshRenderer>().SetPropertyBlock(_propBlock);
        waypoints[currentWaypointIndex - 1].gameObject.SetActive(false);
    }
}
相关推荐
AllBlue4 小时前
unity调用安卓方法
android·unity·游戏引擎
郝学胜-神的一滴5 小时前
Horse3D游戏引擎研发笔记(十):在QtOpenGL环境下,视图矩阵与投影矩阵(摄像机)带你正式进入三维世界
c++·3d·unity·游戏引擎·godot·图形渲染·unreal engine
AllBlue7 小时前
unity导出成安卓工程,集成到安卓显示
android·unity·游戏引擎
Sator110 小时前
Unity的FishNet相关知识
网络·unity·游戏引擎
AllBlue10 小时前
安卓调用unity中的方法
android·unity·游戏引擎
李岱诚11 小时前
epic商城下载,ue4报错处理
游戏引擎·ue4
jtymyxmz1 天前
《Unity Shader》10.1.4 折射
unity·游戏引擎
在路上看风景1 天前
12. Burst
unity
平行云PVT1 天前
实时云渲染解决UE5 像素流插件迁移及传输数据受限问题
unity·ue5·xr·实时云渲染·云桌面·像素流·云推流
熬夜敲代码的小N1 天前
Unity WebRequest高级操作:构建高效稳定的网络通信模块
android·数据结构·unity·游戏引擎