Lerp函數(shù)
Lerp函數(shù)使用的最常見的誤區(qū)是把線性移動用成了彈性移動(關(guān)鍵是自己還不知道,還奇怪,咦,不是說好的線性移動嗎?怎么有點彈性的趕腳……),如下圖所示:

void Update()
{
transform.position = Vector3.Lerp(transform.position, target, 0.1f);
}
這個錯誤主要是沒有理解好Lerp的第三個參數(shù)t的作用,這里我們?yōu)榱吮阌诶斫?,我們拿Mathf.Lerp函數(shù)來分析,思路是一樣的。我們先來看一下Mathf.Lerp函數(shù)的具體實現(xiàn):
/// <summary>
/// <para>Clamps value between 0 and 1 and returns value.</para>
/// </summary>
/// <param name="value"></param>
public static float Clamp01(float value)
{
float result;
if (value < 0f)
{
result = 0f;
}
else if (value > 1f)
{
result = 1f;
}
else
{
result = value;
}
return result;
}
/// <summary>
/// <para>Linearly interpolates between a and b by t.</para>
/// </summary>
/// <param name="a">The start value.</param>
/// <param name="b">The end value.</param>
/// <param name="t">The interpolation value between the two floats.</param>
/// <returns>
/// <para>The interpolated float result between the two float values.</para>
/// </returns>
public static float Lerp(float a, float b, float t)
{
return a + (b - a) * Mathf.Clamp01(t);
}
估計大家一看函數(shù)的實現(xiàn)就明白了關(guān)鍵點,想要線性移動,應(yīng)該只控制t的變化,t的值在0-1,它就類似一個百分比的值,代表著a點到b點之間的位置,比如想要到a和b之間的3/10的位置,t就應(yīng)該是0.3,想要一步到位t的值就應(yīng)該為1。在上述錯誤的用法中,實際的效果就是第一次到達1/10位置,第二次到達1/10+9/10*1/10的位置……理論上講永遠到不了b點,每一次都是a與b點之間的1/10的位置,所以移動的幅度越來越小,有一種彈性感覺。正確的使用方法如下:
private Vector3 target = new Vector3(0, 0, 5);
private Vector3 startPos;
private float t1;
void Start()
{
startPos = transform.position;
}
void Update()
{
t1 += 1f * Time.deltaTime;
transform.position = Vector3.Lerp(startPos, target, t1);
}

SmoothDamp函數(shù)
SmoothDamp函數(shù)在使用過程中比較容易出現(xiàn)的一個問題就是容易在代碼較復(fù)雜的情形下將currentVelocity這個參數(shù)需要的變量定義為局部變量,如下:
public float smoothTime = 0.3F;
void Update()
{
Vector3 velocity = Vector3.zero;
transform.position = Vector3.SmoothDamp(transform.position, target, ref velocity, smoothTime);
}
}
使用局部變量的效果如下圖所示,越來越慢,定義的平滑時間明明是0.3f,怎么用了10幾秒的時間都還在緩慢移動?
為了便于理解,我們來看一下Mathf.SmoothDamp的具體實現(xiàn):
public static float SmoothDamp(float current, float target, ref float currentVelocity, float smoothTime, [DefaultValue("Mathf.Infinity")] float maxSpeed, [DefaultValue("Time.deltaTime")] float deltaTime)
{
smoothTime = Mathf.Max(0.0001f, smoothTime);
float num = 2f / smoothTime;
float num2 = num * deltaTime;
float num3 = 1f / (1f + num2 + 0.48f * num2 * num2 + 0.235f * num2 * num2 * num2);
float num4 = current - target;
float num5 = target;
float num6 = maxSpeed * smoothTime;
num4 = Mathf.Clamp(num4, -num6, num6);
target = current - num4;
float num7 = (currentVelocity + num * num4) * deltaTime;
currentVelocity = (currentVelocity - num * num7) * num3;
float num8 = target + (num4 + num7) * num3;
if (num5 - current > 0f == num8 > num5)
{
num8 = num5;
currentVelocity = (num8 - num5) / deltaTime;
}
return num8;
}
通過具體的實現(xiàn)我們就可以很清楚的發(fā)現(xiàn),currentVelocity這個變量是先使用,然后再賦值,通過ref傳遞就是為了獲取到上一次計算得到的速度值,如果我們使用局部變量,每一次速度都是零,相當于剛開始進行平滑移動,平滑的距離(transform.position到target)不斷在縮短,然而平滑時間卻沒有變化,為了保證大約在平滑的時間內(nèi)完成平滑移動,這個起步速度肯定是越來越慢的,所以就導(dǎo)致了上圖中的問題。
我們把currentVelocity改為全局變量,就可以看到正常效果了
private Vector3 target = new Vector3(0, 0, 5);
public float smoothTime = 0.3F;
private Vector3 velocity = Vector3.zero;
void Update()
{
transform.position = Vector3.SmoothDamp(transform.position, target, ref velocity, smoothTime);
}
效果如下:
