[Unity] Dreamteck Splines实现沿路径移动功能
Dreamteck Splines实现沿路径移动功能
最近有一个“让物体沿固定路径移动”的需求,因此接触到了Dreamteck Splines插件。
Dreamteck Splines可以很方便地绘制各种插值曲线,但在实现物体移动的时候却遇到了很多坑,因此在这里记录一下。
1. 绘制路径线
首先,让我们在场景上创建一个空物体,并添加SplineComputer组件。

由于我这是个2D项目,所以选择在Z平面上绘制。

之后编辑器中就会显示出跟随鼠标的网格线,点击左键就可以逐点绘制Spline了。


在右侧选项中可以修改Spline的类型。默认类型是Catmull Rom,我们可以把它改成直线Linear。


2. 获取坐标
SplineComputer类有两类获取坐标点的方法:
GetPoint(int)GetPoints()
这两个方法用于获取我们手动添加的坐标点,也就是我们上图中的那三个点。这明显不符合我们“沿路径移动”的需求。
而下面这三个方法才是返回Spline上的所有坐标点
Evaluate(double)EvaluatePosition(double)EvaluatePositions()
其中,Evaluate和EvaluatePosition的区别在于,Evaluate返回的是SplineSample对象,包括了坐标、朝向、颜色、百分比等信息,而EvaluatePosition则是简单地返回一个Vector3的坐标。在只需要坐标的情况下,推荐使用更加轻量化的EvaluatePosition。
3. 移动示例(踩坑)
EvaluatePosition(double)方法传入一个0~1的值,就会返回Spline上对应的坐标,因此我们可以用这个脚本手动模拟物体的移动过程。
using Dreamteck.Splines;
using UnityEngine;
public class Move : MonoBehaviour
{
[Range(0, 1)]
public float Percent;
public Transform Target;
private SplineComputer spline;
void Start()
{
spline = GetComponent<SplineComputer>();
}
void Update()
{
Target.position = spline.EvaluatePosition(Percent);
}
}
将脚本挂载到SplineComputer所在的物体上,拖动右侧的滑动条即可移动目标物体。

一切看似十分正常,直到我们又添加了一条长度不同的线段。

可以明显地看出,在后面这个较短的路径中,物体的移动速度明显变慢了。
当我们直接将进度设为0.5后,便能发现问题所在。

目标物体移动并没有移动到Spline的终点,而是移动到了我们设置的第二个控制点上。
这个问题在官方文档的3.3. Sample Mode中有对应的解答:
默认情况下,样条曲线(Spline)在 [0-1] 的百分比范围内进行计算(evaluated),涵盖了所有坐标点。
例如,一条由 3 个点组成的样条曲线,计算百分比为 0.5 的坐标点,将始终返回第二个点的位置,因为它位于中间。
然而,如果第一个点和第二个点非常接近,而第三个点距离它们很远,计算百分比为 0.5 的坐标点不会返回样条曲线的中间位置,它仍将返回第二个点。因为某些区域的采样点比其他区域更密集。
为了说明这一点,以下是显示了采样点密度的样条曲线:每条垂直线表示一个采样点(spline sample)。在这种情况下,点 1 和点 2 之间有 10 个采样点,但点 2 和点 3 之间也只有 10 个采样点。
从中我们可以看出,问题的根源在于,Evaluate参数中的percent并不是指Spline长度的百分比,而是表示Spline采样点的百分比。而采样点的不均匀分布,导致了采样点百分比和长度百分比不一致的情况。
5 方法一:修改采样模式(Sample Mode)
前面我们提到"采样点的不均匀分布,导致了采样点百分比和长度百分比不一致的情况"。
反过来说,我们只需要让采样点能够均匀分布,就可以解决这一问题。
SplineComputer提供了三种采样模式(Sample Mode):
- Default(默认):两点间的采样点数量固定

- Uniform(均匀):根据Spline长度,均匀分布采样点。但在Spline较长时会有更大的性能开销。

- Optimized(优化):与默认模式相同,但会执行优化操作删除不必要的采样点

所以我们需要选择Uniform模式,以实现均匀分布采样点的需求。
请注意,在Default和Optimized模式下,当移动控制点时,Spline仅更新受该点影响的区域中的采样点。而在Uniform模式下,将重新计算整个Spline。在Optimized模式下,还提供了一个额外的滑块来控制优化的角度阈值。

这样一来就能正确地匀速移动目标了

但是!
除了性能开销外,这个方法还会带来一系列问题。
首先,它会导致线段脱离控制点:

其次,它还有个很致命的BUG
Uniform模式下,如果你用CalculateLength方法获取Spline的长度,那么初始状态下将会始终返回0。此时必须对他"进行一些操作",比如移动控制点,修改其他参数等,让他响应一次变化。之后CalculateLength才能正确返回数值。

6 方法二:使用Travel函数(推荐)
为了避免上述问题,我们可以使用Travel函数计算某个长度在Spline上对应的采样点百分比。
它的使用方法在官方文档的20.4. Converting World Units to Spline Percentages中有所提及。
假如我们要获取Spline中心点的坐标,只需要传入Spline长度的一半,也就是spline.CalculateLength() / 2,然后Travel函数就会返回对应的percent。这时再调用EvaluatePosition(percent)即可得到中心点的坐标。其他位置的坐标也是同理,我们只需要给出对应的长度即可获取坐标。
这样一来,我们就可以方便地实现沿路径匀速移动的功能了。
using Dreamteck.Splines;
using UnityEngine;
public class Move : MonoBehaviour
{
[Range(0, 1)]
public double Percent;
public float Speed;
public Transform Target;
private float distance;
private SplineComputer spline;
void Start()
{
spline = GetComponent<SplineComputer>();
distance = 0;
}
void Update()
{
distance += Speed * Time.deltaTime;
// 有需要的话可以用这个限制上限
// distance = Math.Min(distance, spline.CalculateLength());
Percent = spline.Travel(0, distance);
Target.position = spline.EvaluatePosition(Percent);
if (Percent == 1)
{
// do something
Debug.Log("Done");
}
}
}
效果如下


参考资料
Dreamteck Splines – User Manual
本文发布于2024年7月14日
最后编辑于2024年7月14日
[Unity] Dreamteck Splines实现沿路径移动功能的更多相关文章
- 【转载】利用Unity自带的合图切割功能将合图切割成子图
虽然目前网上具有切割合图功能的工具不少,但大部分都是自动切割或者根据plist之类的合图文件切割的, 这种切割往往不可自己微调或者很难维调,导致效果不理想. 今天逛贴吧发现了一位网友写的切割合图插件很 ...
- Unity中几个特殊路径在各个平台的访问方式
1.文件路径Resources:Unity在发布成移动端项目后,其他文件路径都将不存在,但是如果有一些必要的资源,可以放在Resources文件夹下,因为这个文件夹下的所有资源是由Unity内部进行调 ...
- C# Unity依赖注入利用Attribute实现AOP功能
使用场景? 很多时候, 我们定义一个功能, 当我们要对这个功能进行扩展的时候, 按照常规的思路, 我们一般都是利用OOP的思想, 在原有的功能上进行扩展. 那么有没有一种东西, 可以实现当我们需要扩展 ...
- unity中的文件存储路径与各平台(Android,iOS)的关系
原文链接:unity中的文件存储路径与各平台(Android,iOS)的关系 主要是这个问题困扰我了一阵子,所以特写写... unity中的的各种存储方法的对应关系(直接上截图吧) 重点说的是Appl ...
- Unity Procedural Level Generator 基础总结与功能优化
Procedural Level Generator是在Unity应用商店中发布的一款免费的轻量级关卡生成器: 可以直接搜索关键字在应用商店中查找并下载. 和我之前生成关卡的想法不同,这个插件生成地图 ...
- Unity 的 unitypackage 的存放路径
Windows,C:\Users\<username>\AppData\Roaming\Unity\Asset Store Mac OS X,~/Library/Unity/Asset S ...
- Unity在安卓的一些路径
APK安装之后找不到路径 公司的测试机(安卓)基本都是不带SD卡的. APK在安卓手机上安装之后,使用手机助手类的软件打开文件管理,打开 内置SDK卡/Android/data/ 在这个目录下却发现 ...
- Unity添加多个可视镜头Preview功能(二)
制作好并摆放好镜头以后,在Preview.cs里添加一个time单个镜头移动时间的变量,并在PreviewEditor下绘制在Inspector面板下. 然后,添加一个FollowPreviewPat ...
- 【Unity】自定义编辑器窗口——拓展编辑器功能
最近学习了Unity自定义编辑器窗口,下面简单总结,方便用到时回顾. 新建一个脚本: using UnityEngine; using System.Collections; using UnityE ...
- 【Android】3.13 路径规划功能
分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 一.简介 线路规划支持以下功能: 公交信息查询:可对公交详细信息进行查询: 公交换乘查询:根据起.终点,查询策 ...
随机推荐
- C数据结构线性表:最全链表实战剖析—单 双 循环链表&增删改查
文章目录 前言 说明1 说明2 A:关于为什么传链表要用二级指针 B:单链表 1:定义结构体 2:初始化链表 3:销毁链表内容 (释放整个链表空间,把L指针赋值为NULL ) 4:增加某一个位置上的元 ...
- C 语言中的 sscanf 详解
一.函数介绍 函数原型:int sscanf(const char *str, const char *format, ...); 返 回 值:成功返回匹配成功的模式个数,失败返回 -1. RETUR ...
- vue我自己的动态菜单思路
1.在router里把所有的路由都加上. 2.后端存储路由path和其他设计需要的信息. 3.登录后,后端返回菜单树,根据权限不同,返回的菜单不同,并且还要返回每个path代表的页面具有的权限数组.可 ...
- Android 13 - Media框架(15)- OpenMax(三)
关注公众号免费阅读全文,进入音视频开发技术分享群! 上一节学习了 media.codec 服务中的部分内容,这一节我们将一起了解 OMX IL 层的 API 以及相关的结构体等内容. 1.相关路径 以 ...
- .NET桌面程序混合开发之二:在原生WinFrom程序中使用WebView2
本文将介绍如何在WinForms中嵌入WebView2,并讲到WebView2的主要特征.点击了解更多WebView2的API. 1. 准备 Visual Studio 2017 及以上版本 WebV ...
- Qt-FFmpeg开发-打开本地摄像头录制视频(7)
音视频/FFmpeg #Qt Qt-FFmpeg开发-打开本地摄像头录制视频[软解码+ OpenGL显示YUV] 目录 音视频/FFmpeg #Qt Qt-FFmpeg开发-打开本地摄像头录制视频[软 ...
- FFMPEG 信息查询
一.问题描述 最近测试反馈一个隐私模式的问题,主播端启用隐私模式之后,在观看端发现画面转菊花并且还有回跳的现象 二.问题分析: 从网上下载了直播的视频文件,进行了一下分析,发现视频长度和音频长度不匹配 ...
- 阅读LXH《FFMPEG+SDL的视频播放器》总结
一.原文地址 https://blog.csdn.net/leixiaohua1020/article/details/46889389 在此向雷霄骅致敬!!! 二.视频播放器实现思路 1)视频播放器 ...
- ChatTTS,语气韵律媲美真人的开源TTS模型,文字转语音界的新魁首,对标微软Azure-tts
前两天 2noise 团队开源了ChatTTS项目,并且释出了相关的音色模型权重,效果确实非常惊艳,让人一听难忘,即使摆在微软的商业级项目Azure-tts面前,也是毫不逊色的. ChatTTS是专门 ...
- 初识c语言—c语言的初步认识和一个简单的程序
C语言是什么 编程语言(编程语言是控制计算机的一系列指令,他又固定的格式和词汇.同时也叫计算机语言(计算机语言是,人和计算机通讯的语言)) C语言的特点 语言简洁,紧凑,使用方便 运算符丰富 数据类型 ...


