博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity中物体移动方法详解
阅读量:1985 次
发布时间:2019-04-27

本文共 4360 字,大约阅读时间需要 14 分钟。

一.Transform

1.transform.Translate

不会考虑到碰撞。

transform.Translate(Vector3 targetPos,指定参照坐标系(默认为Space.Self))

 

2.transform.position

我认为Transform严谨来说并不能称作移动,而是直接改变物体的坐标。

transform.position(vector3 targetPos)

targetPos是指定的坐标位置。
 

二.刚体

1.MovePosition()

2.velocity

使物体忽略静摩擦力,从静止状态快速进入运动状态。

3.AddForce()

给物体添加一个方向力。
 

三.角色控制器

1.SimpleMove()

模拟重力,返回值表示当前角色是否着地。

2.Move()

不模拟重力,返回值表示角色于周围的碰撞信息。
 

四.平滑

1.Lerp()——线性插值移动(Vector2.Lerp,Vector3.Lerp,Mathf.Lerp,Quaternion.Lerp,Color.Lerp,Material.Lerp)


在Mathf中,Lerp函数是这样的:Lerp(float a,float b,float t)。

a是起始位置,b是结束位置,t是一个比例因数,t可以用作为时间单位,但并不能理解为时间,是一个[0,1]的值,t=0时返回a,t=1时返回b。


首先说明一下Lerp函数的计算公式是如何推导出来的:t(b-a)+a。

假如从起始点a点到目标点b点,当前运动到的点为c点,需要求出已经运动的距离占总距离的多少,也就是a和c的距离占a和b的距离的比例。
那么t=(c-a)/(b-a),解出tb-ta=c-a,所以t(b-a)=c-a,则c=t(b-a)+a。


之后看一下Lerp的内部实现:用Clamp01函数去限制t的范围,之后再用计算公式:a+(b-a)*t计算每帧到达的位置。

 


对于Lerp之前一直有一个误区就是认为它是减速运动,其实它的运动类型是由参数决定的。

我测试出来了用它可以实现减速运动,先加速后减速,匀速运动。
其实都是利用公式a+(b-a)*t变换的。
1.如果想实现减速运动,代码如下图。
观察Cube的运动或者观察Inspector面板中X的值,发现变化的越来越慢,而且x的值永远不等于目标值只能无限接近目标值,最大为7.999999。
因为Time.deltaTime每帧是一样的,例如0.1。所以用公式a+(b-a)*t计算可知。
第一帧:0+(8-0)*0.1=0+0.8=0.8   比上一帧多移动了0.8
第二帧:0.8+(8-0.8)*0.1=0.8+0.72=1.52   比上一帧多移动了0.72
第三帧:1.52+(8-1.52)*0.1=1.52+0.648=2.168   比上一帧多移动了0.648
第四帧:以此类推。
发现每帧移动的距离都在减少,这是由于起始点位置是变化的所导致的。
 

2.如果想实现先加速后减速运动,代码如下图。

Time.time只能用于程序一开始就运动的物体,如果在程序中再使用Time.time将会一帧直接到达目标值,因为Time.time早已经大于1。
观察Cube的运动或者观察Inspector面板中X的值,发现变化的越来越快,X坐标的值是可以到达目标值的。
例如每帧Time.time增加0.1秒,用公式a+(b-a)*t计算可知。
第一帧:0+(8-0)*0.1=0+0.8=0.8   比上一帧多移动了0.8
第二帧:0.8+(8-0.8)*0.2=0.8+1.44=2.52   比上一帧多移动了1.44
第三帧:2.52+(8-2.52)*0.3=2.52+1.644=4.164    比上一帧多移动了1.644
第四帧:以此类推。
发现每帧移动的距离先增加后减少,这是由于起始点的位置和比例因数一直变化所导致的。
当Time.time=1时也就是游戏运行一秒钟时,Cube到达目标值。这段代码的含义就是让Cube在一秒钟内从起始点到达目标点。
 

3.如果想实现匀速运动,代码如下图

观察Cube的运动或者观察Inspector面板中X的值,发现变化的非常匀速,X坐标的值是可以到达目标值的。
例如每帧Time.time增加0.1秒,用公式a+(b-a)*t计算可知。
第一帧:0+(8-0)*0.1=0+0.8=0.8   比上一帧多移动了0.8
第二帧:0+(8-0)*0.2=0+1.6=1.6   比上一帧多移动了0.8
第三帧:0+(8-0)*0.3=0+2.4=2.4   比上一帧多移动了0.8
第四帧:以此类推。
发现每帧移动的距离都是不变的,这是由于起始点和目标点的位置是不变的,只由比例因数决定。
当Time.time=1时也就是游戏运行一秒钟时,Cube到达目标值。这段代码的含义就是让Cube在一秒钟内从起始点到达目标点。

如果想让物体在time秒后到达目标点呢?

1.改变Time.deltaTime

首先我们不设置到达目标点的时间,如下图代码所示:
比例因数t每帧加上Time.deltaTime则游戏运动一秒钟后到达目标位置,因为Time.deltaTime的值是1/帧率,假如每秒50帧那么一秒后t的值将会变为1。
如果需要设置到达目标点的时间,如下图代码所示:
因为Time.deltaTime的值是1/帧率,所以可以列一个等式。
也就是说乘以1/time后t值的增长速度变慢了,需要之前time倍的时间才可以到达1。
2.改变Time.time(不推荐)
Time.time只适用于游戏一开始时运动的情况。如果在游戏过程中运动则Time.time有可能早已大于0。

 

2.SmoothDamp()——平滑阻尼移动(Vector2.SmoothDamp,Vector3.SmoothDamp,Mathf.SmoothDamp)

由Damp可知是一个阻尼移动所以会受到阻力而减速,也就是越来越慢。


在Mathf中,SmoothDamp是这样的:Mathf.SmoothDamp(float current, float target, ref float currentVelocity, float smoothTime, float maxSpeed)。

current是当前位置,target是目标位置,currentVelocity是当前速度(必须是一个全局变量),smoothTime是到达目标位置的时间,maxSpeed是最大速度(默认为无穷大)。


首先看一下SmoothDamp是如何实现的:

因为它不像Lerp那么简单它的内部参数经过了很多次的调整所以效果会更加平滑,常用于相机跟随操作。
3.MoveTowards()——平滑移动(Vector2.MoveTowards,Vector3.MoveTowards,,Mathf.MoveTowards)


Math.MoveTowards(float a,float b,float maxDelta)

a是起始位置,b是结束位置,maxDelta是每次向目标点移动的距离,maxDelta是一个[-∞,b]的值。
如果maxDelta大于0则物体逼近目标点移动,如果maxDelta小于0则物体远离目标点移动。
 


注意maxDelta是每次向目标点移动的距离。

1.物体放在原点,x值从0运动到10,maxDelta是一个正值。
运行后发现物体朝目标点的正方向移动。
2.物体放在原点,x值从0运动到10,maxDelta是一个负值。
运行后发现物体朝目标点的负方向移动。
3.物体放在x为10的位置,x值从10运动到0,maxDelta是一个正值。
运行后发现物体朝目标点的正方向移动。
4.物体放在x为10的位置,x值从10运动到0,maxDelta是一个负值。
运行后发现物体朝目标点的负方向移动。
 


下面都是各种不同的测试:

首先是一种没什么使用价值的做法。
设置a,b,maxDelta的值都是定值,代码如下图。
运行后发现物体停在x为1的位置永远不发生运动。
其次还是一种没什么使用价值的做法。
设置a,maxDelta是定值,b为变化的,代码如下图。
运行后发现物体从0缓慢运动到1之后不再运动。
其实MoveTowards函数的参数a一般是当前物体的自身位置,是一个变化的值,而b和maxDelta为定值。
既然maxDelta是一个(-∞,b]的定值,那么当它的值属于不同区间时是如何变化的呢?

例如a=当前的a,b=5时。

当maxDelta为负数时,物体向目标点的相反方向运动。
当maxDelta为0时,物体原地不动。
当maxDelta为5时,物体一帧就会移动到目标位置。
当maxDelta为5.1时,物体一帧就会移动到目标位置,并不会超过b的值。
所以maxDelta是代表了每次朝目标点移动的距离,最大只能是目标位置的值。


那如果想让物体在time秒后到达目标点呢?

4.Slerp()——球形插值(Vector3.Slerp,Quaternion.Slerp)

 

五.特殊

1.Mathf.PingPong(float t,float length)——乒乓运动


Mathf.PingPong(float t,float length)

t是一个[0,length]的值,是一个需要变化的值。


官方的实例用法(不推荐):

Time.time只适用于游戏一开始时运动的情况。如果在游戏过程中运动则Time.time并不是从0开始计算的。
运行后发现物体的x坐标在0到4之前来回运动。

那如果想让物体在time秒后到达目标点再回到起始点来回运动呢?

首先如果不设置时间,代码如下图所示:

运行后发现物体的x坐标在0到10之间来回运动,一去一回的时间分别都是10秒。
如果需要设置到达目标点的时间,
代码如下图所示:
运行后发现物体的x坐标在0到10来回运动,一去一回的时间分别都是5秒。
如果想让物体不从0开始运动,而是指定的位置,代码如下图所示:
因为sum的值是在0到target之间运动,那么加上指定开始位置的值,就实现了功能。
运行后发现物体的x坐标在5到15来回运动,一去一回的时间分别都是10秒。

注意PingPang的内部实现中,length会作为分子出现,如果length为0时会报NaN(Not a Number)的错误。

Unity中关于NaN的问题:
 

3.Math.Repeat(float t,float length)

返回一个[t,length)的值,t是一个变化的值。

转载地址:http://jvyvf.baihongyu.com/

你可能感兴趣的文章
【工具与环境】Windows下安装Sublime Text 3
查看>>
【工具与环境】Excel中批量插入行
查看>>
【学习笔记】对vanilla的一些个人理解
查看>>
“学硕” VS “专硕”
查看>>
【NLP学习笔记】知识图谱阅读笔记及其心得
查看>>
【工具使用】新版CSDN-markdown编辑器使用指南
查看>>
《知识图谱》阅读笔记(六)
查看>>
【NLP学习笔记】中文分词(Word Segmentation,WS)
查看>>
【NLP学习笔记】词性标注(Part-of-speech Tagging, POS)
查看>>
【超越白皮书7】你需要知道关于ETH2.0的几个事实
查看>>
AMM做市无常损失对冲分析系列(一)—— 损益及期权对冲模型构建
查看>>
【python练习题】遍历1
查看>>
对于时间复杂度的通俗理解
查看>>
如何输入多组数据并输出每组数据的和?
查看>>
基于CentOS 7的Linux常用命令行命令
查看>>
行阶梯型矩阵
查看>>
matlab中uint8,double,im2double和im2uint8的区别
查看>>
SVM进行人脸检测
查看>>
C++学习笔记
查看>>
图像处理学习笔记
查看>>