Unity 简单载具路线 Waypoint 导航

news2024/11/18 12:37:34

前言

在游戏开发和导航系统中,"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)icon-default.png?t=N7T8https://dotween.demigiant.com/index.php

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

  2. 在场景中增加你的路径点,做一个父物体,然后为子物体增加多个路径点,这里每个路径点建议使用带有方向的模型或者图片,这样便于查看
  3. 为你的载具添加文末的脚本,并挂在载具上(如果你不想挂在载具上,那简单改一下代码的变量为你的期望物体上就行)。
  4. 在inspector中绑定好你需要的路径点集合的父物体(wayPointsParent变量),这里我在父物体上额外加了一个LineRender组件,用于后续连线效果:
  5. 运行程序!车子就会动起来了!调节每一个变量,让车子移动的更自然!
    每个变量都有它的意义,比如你可以规定整个路程的总时间、转一次弯需要多少时间,转弯的起始距离阈值以及每到一个waypoint的事件调用等等,并可以更具每个人的需要自行修改和拓展!

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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1900271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【课程总结】Day13(下):人脸识别和MTCNN模型

前言 在上一章课程【课程总结】Day13(上):使用YOLO进行目标检测,我们了解到目标检测有两种策略,一种是以YOLO为代表的策略:特征提取→切片→分类回归;另外一种是以MTCNN为代表的策略:先图像切片→特征提取→分类和回归。因此,本章内容将深入了解MTCNN模型,包括:MTC…

WPF UI 3D 多轴 机械臂 stl 模型UI交互

1、三维插件环境调整 2、动态模型材质处理 3、动态模型鼠标交互 4、模型旋转基本思路 5、六轴机械臂节点旋转处理 6、更多HelixToolkit插件处理案例 7、快速对接Blender模型 鼠标交互&#xff08;没有强调场景的变换&#xff09; 鼠标命中测试&#xff08;HitTest 不推荐&…

uni-app x 跨平台开发框架

目录 uni-app x 是什么 和Flutter对比 uts语言 uvue渲染引擎 组合式API的写法 选项式API写法 页面生命周期 API pages.json全局配置文件 总结 uni-app x 是什么 uni-app x&#xff0c;是下一代 uni-app&#xff0c;是一个跨平台应用开发引擎。 uni-app x 是一个庞…

基于STM32与ESP8266的智能电表设计与实现:实时监测,远程管理(附代码实例)

一、项目背景 随着物联网技术的快速发展&#xff0c;传统电表已经无法满足智能电网对用电信息采集、分析和管理的需求。智能电表作为新一代电能计量设备&#xff0c;具有实时监测、远程抄表、用电分析等功能&#xff0c;是实现智能电网的重要基础设施。 本项目旨在设计并实现…

Exploting an API endpoiint using documentation

HTTP request methods https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods 第一步:burp抓包刷新页面 httphistory中只能看到两个记录,可以看下Response,是HTML页面,说明这里有HTML页面 ,但是没有发现特定的API接口。 第二步:用户登录 转到用户登录的功能点处…

kubernetes集群部署:环境准备及master节点部署(二)

主机名IPv4地址IPv6地址角色安装组件操作系统k8s130-node190192.168.XX.190240a:XX::190masterkubeadm、kubelet、containerdAnolis OS 8.94.19.91-28.1.an8.x86_64k8s130-node191192.168.XX.191240a:XX::191nodekubeadm、kubelet、cri-oAnolis OS 8.94.19.91-28.1.an8.x86_64k…

Rust作用域和遮蔽

作用域和遮蔽 变量绑定有一个作用域&#xff08;scope&#xff09;&#xff0c;它被限定只在一个代码块&#xff08;block&#xff09;中生存&#xff08;live&#xff09;。 代码块是一个被 {} 包围的语句集合。另外也允许[变量遮蔽][variable-shadow]&#xff08;variable s…

SwiftUI 6.0(iOS 18.0)滚动视图新增的滚动阶段(Scroll Phase)监听功能趣谈

何曾几时&#xff0c;在 SwiftUI 开发中的秃头小码农们迫切需要一种能够读取当前滚动状态的方法。 在过去&#xff0c;他们往往需要借助于 UIKit 的神秘力量。不过这一切在 SwiftUI 6.0 中已成“沧海桑田”。 在本篇博文中&#xff0c;您将学到如下内容&#xff1a; 1. Scroll…

Python入门 2024/7/6

目录 数据容器入门 列表的定义语法 基本语法 嵌套列表 ​编辑 列表的下表索引 ​编辑 列表的常用操作 列表的常见方法 查找元素的下标 修改下标索引的值 插入元素 追加元素 追加一批元素 删除元素 删除某元素在列表中的第一个匹配项 清空列表内容 统计元素在…

【Unity URP】通过代码动态添加URP渲染通道RendererFeature

URP的渲染通道RendererFeature可以很方便的实现一些渲染问题,比如渲染顺序问题,遮挡后的材质替换等等。 那么我们如何通过代码来动态添加和修改呢? 首先我们需要获取到当前的URP配置文件,在对配置文件进行添加 1.通过反射获取当前UniversalRendererData 我们通过Graphic…

Day05-03-Nexus仓库

Day05-03-Nexus仓库 05-nexus-仓库1. 概述2. 极速部署指南2.1 下载2.2 部署2.3 配置2.4 连接使用nexus2.4 编译与测试 3. 总结 05-nexus-仓库 1. 概述 背景: maven编译的时候&#xff0c;npm/cnpm编译&#xff0c;需要下载大量的依赖包。这些依赖包在每一次构建的时候都需要使…

解决Docker Desktop启动异常 Docker Desktop- WSL distro terminated abruptly

异常 当打开Docker Desktop时候&#xff0c;启动docker引擎时&#xff0c;提示 加粗样式文本信息 Docker Desktop - WSL distro terminated abruptly A WSL distro Docker Desktop relies on has exited unexpectedly. This usually happensas a result of an external entit…

.net 调用海康SDK的跨平台解决方案

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔序言 上2篇海康SDK使用以及常见的坑…

C++11 shared_ptr---面试常考

shared_ptr简介 共享对其所指堆内存空间的所有权&#xff0c;当最后⼀个指涉到该对象的shared_ptr不再指向他时&#xff0c;shared_ptr会⾃动析构所指对象如何判断⾃⼰是否指涉到该资源的最后⼀个&#xff1f;《引⽤计数》 shared_ptr构造函数&#xff0c;使引⽤计数析构函数&…

【docker nvidia/cuda】ubuntu20.04安装docker踩坑记录

docker nvidia 1.遇到这个错误&#xff0c;直接上魔法(科学上网) OpenSSL SSL_connect: Could not connect to nvidia.github.io:443 这个error是运行 NVIDIA官方docker安装教程 第一个 curl 命令是遇到的 2. apt-get 更新 sudo apt update遇到 error https://download.do…

横截面交易策略:概念与示例

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

考CFA ESG踩过的坑,想考CFA ESG的同学,可以收藏

考CFA ESG踩过的坑 考证也是蹭热点&#xff0c; 2020年&#xff0c;那时是云&#xff0c;阿里云&#xff0c;腾讯云&#xff0c;华为云竞相绽放&#xff0c; 再过点时间&#xff0c;好像安全方面的证书&#xff0c;如油炸爆米花一样&#xff0c;噼里啪啦地蹦了出来&#xff0…

matlab 抛物线图像绘制

抛物线图像绘制 x^2y4绘制结果 x^2y4 clc,clear,close all; length10; % 创建一个范围内的 x 和 y 值 x linspace(-length, length, 1000); y linspace(-length, length, 1000);% 创建一个网格来表示 x 和 y 值的组合 [X, Y] meshgrid(x, y);% 计算方程的左边和右边的值 LH…

AIGC | 在机器学习工作站安装NVIDIA CUDA® 并行计算平台和编程模型

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路 ] 0x02.初识与安装 CUDA 并行计算平台和编程模型 什么是 CUDA? CUDA&#xff08;Compute Unified Device Architecture&#xff09;是英伟达&#xff08;NVIDIA&#xff09;推出的并行计算平台和编…

Docker 部署 Nacos v2.3.2 版本

文章目录 Github官网文档Nacos 生态图Nacos Dockerdocker-compose.ymlapplication.propertiesNacos 官方示例 Github https://github.com/alibaba/nacos 官网 https://nacos.io/ 文档 https://nacos.io/docs/latest/what-is-nacos/ Nacos 生态图 Nacos Docker 镜像&…