有时,我们在做游戏时会发现有些跟随动作不够圆滑或者需要一个缓冲的效果,这时,一般会考虑到插值。所以对插值的理解是必需的。(比如摄像机跟随主角)
插值是数学上的一个概念,在这里用公式表示就是:from + (to - from) * t;这也就是Lerp的返回值(用这个公式分别算出x,y,z)。
static function Lerp (from : Vector3, to : Vector3, t : float) : Vector3
from 是起始的位置,to是目标位置,按照数字t在from到to之间插值。这句话比较难理解,下面举个例子。
这和我们用公式算出来的如出一辙。现在我们再看一个具体的例子
//在1秒时间动画位置移动从from开始到to结束。(这是官方的例子)
位置移动从start开始到end结束,这好理解,但是为什么是1秒呢?
Time.time是从0开始随时间增加的。
例1的t是一个固定的值,返回一个固定的向量。此时t是变量,在不断增加。那么:
当Time.time = 0时--->transform.position = start.position,位置没有变化;
当Time.time从0趋向于1时--->transform.position 不断接近start.position,该脚本是挂在start物体上的,所以start会不断靠近end。
那么问题来了,当Time.time>1的时候,会怎么样呢?额(⊙o⊙)…我们说不会。
由上面的公式from + (to - from) * t可知,当t=1时,to - from = 0,此时t就无效了。
例1是从静态角度看,例2是从动态角度看的(两个变量,一个是时间在变化,一个是位置在变化)。
想一想例2,如果不是Time.time,而是0.5,会怎么样?(只看一个变量)
由图易知:A物体会不断以0.5的比例无限接近于B。
如果上面都理解了,那么看官方的第二个例子就没什么问题了,试一试吧!
//像弹簧一样跟随目标物体
Lerp函数在Mathf,Vector3, 等类中都有,用法都类似,作用都是按照百分比取得从一个值过度到另外一个值的中间值。下面说的内容针对各中类的Lerp函数都是通用的。
Lerp的常见“误用”是
Update()
{
Transform.position = Vector3.Lerp(transform.position.x, targetPosition, Time.deltaTime);
}
说是“误用”,其实也不完全正确,这种用法是可以工作的,但是常常不是大家的真正需求,很多时候大家使用Lerp都是想达到匀速运动的效果,但如下“误用”却让对象以逐渐降低的速度运动。
首先,上述“误用”是这样工作的:每帧都重新获取物体当前的位置,计算物体和目标距离的差距,再按照当前帧的持续时间(当做一个百分比)来移动这个比例的位置。因此如果目标位置始终是固定的,那么整体运动是缓动的,先快后慢。这样的效果乍一看还不错,但其实是有一些问题的:因为每秒钟都以固定的比例靠近目标位置,所以运动速度会以固定的比例逐渐降低,只要运算精度够高,运动永远达不到目标,且运算始终在进行。如果确实需要这样做,那么我们需要加上一个阈值,当与目标距离小于这个阈值时,就直接把物体的位置设置为目标位置。这个阈值的大小设置要合适,太大了在后面阶段会感觉到明显的跳跃,太小了会浪费运算时间。
这里说明一下,如果上述效果就是我们想达到的目标,那么用Time.deltaTime作为第三个参数在这个情况下是有道理的,因为每帧时间不同,为了保证单位时间内运动的百分比是一致的(达到平滑缓动的效果),需要用Time.deltTime介入。
如果你是误打误撞实现了缓动效果,并且觉得效果不错就没有再深究了,那么建议你继续往下看看。
用Lerp来实现匀速运动的代码
先看代码:
float speed = 2.0f;
//什么时候开始运动
float startTime = 2.0f;
//起始X位置
float startX = 0.0f;
//结束X位置
float endX = 0.0f;
void Update()
{
float lerpValue = Mathf.Lerp(startX,endX,(Time.time-startTime )* speed);
transform.position = new Vector3(lerpValue,0,0);
}
一定要理解清楚Mathf.Lerp(float a, float b, float t)第三个参数t的意义,它是一个百分比,最小值有效值是0,最大有效值是1,如果超出了1,就取1,小于0则取0.
它表示从a到b之间,按照t这个百分比来取值,例如a是0,b是100,如果t是0.2,则该函数返回的值是20,如果t是1,该函数返回的值为100.
匀速运动的要点是起始值和结束值都是固定好的,不会随着运动而发生变化。
Time.time就是系统运行时间,也就是这个程序开始到现在的时长。
(Time.time - startTime),上面例子中startTime是2.0f,那么这个式子的取值一开始是-2,2秒时变成0,3秒时变成1,先假设没有乘以speed这个值,整个运动过程会在2秒开始,3秒结束。
物体运动的速度是距离差(在本例中是10.0f)除以1秒。乘以一个speed以后,实际上是在调整整体的运动时间。
假设speed为0.1f,则运动的时间变为2秒开始12秒结束,运行时间变成了10,则速度变成原先的1/10,
同理,假设speed 为10f,则运动时间变为2秒开始2.1秒结束,速度变成原先的10倍。