應用運動

Vector3 結構包含一些靜態函式,當我們希望將運動應用於 Vector3 時,這些函式可以提供效用。

LerpLerpUnclamped

lerp 函式基於提供的分數提供兩個座標之間的移動。如果 Lerp 只允許兩個座標之間的移動,則 LerpUnclamped 允許分數移動到兩個座標之間的邊界之外。

我們提供運動的一部分作為 float。使用 0.5 的值,我們找到兩個 Vector3 座標之間的中點。01 的值將返回第一個或第二個 Vector3,因為這些值或者與沒有移動(因此返回第一個 Vector3)或完成移動(這返回第二個 Vector3)相關聯。重要的是要注意,這兩個函式都不適應運動分數的變化。這是我們需要手動解決的問題。

使用 Lerp,所有值都夾在 01 之間。當我們想要向一個方向提供移動而不想超越目的地時,這非常有用。LerpUnclamped 可以取任何值,可用於提供遠離目的地或經過目的地的移動。

以下指令碼使用 LerpLerpUnclamped 以一致的速度移動物件。

using UnityEngine;

public class Lerping : MonoBehaviour
{
    /// <summary>The red box will use Lerp to move. We will link
    /// this object in via the inspector.</summary>
    public GameObject lerpObject;
    /// <summary>The starting position for our red box.</summary>
    public Vector3 lerpStart = new Vector3(0, 0, 0);
    /// <summary>The end position for our red box.</summary>
    public Vector3 lerpTarget = new Vector3(5, 0, 0);

    /// <summary>The blue box will use LerpUnclamped to move. We will 
    /// link this object in via the inspector.</summary>
    public GameObject lerpUnclampedObject;
    /// <summary>The starting position for our blue box.</summary>
    public Vector3 lerpUnclampedStart = new Vector3(0, 3, 0);
    /// <summary>The end position for our blue box.</summary>
    public Vector3 lerpUnclampedTarget = new Vector3(5, 3, 0);

    /// <summary>The current fraction to increment our lerp functions by.</summary>
    public float lerpFraction = 0;

    private void Update()
    {
        // First, I increment the lerp fraction. 
        // delaTime * 0.25 should give me a value of +1 every second.
        lerpFraction += (Time.deltaTime * 0.25f);

        // Next, we apply the new lerp values to the target transform position.
        lerpObject.transform.position 
            = Vector3.Lerp(lerpStart, lerpTarget, lerpFraction);
        lerpUnclampedObject.transform.position 
            = Vector3.LerpUnclamped(lerpUnclampedStart, lerpUnclampedTarget, lerpFraction);
    }
}

紅色框移動到目標位置,然後停止。藍框繼續無限移動。

MoveTowards

MoveTowards 的表現 Lerp 非常相似 ; 核心不同的是,我們提供了一個實際的距離來移動,而不是一個,分數的兩個點之間。值得注意的是,MoveTowards 不會超過目標 Vector3

LerpUnclamped 非常相似,我們可以提供一個距離值來遠離目標 Vector3。在這種情況下,我們永遠不會超越目標 Vector3,因此運動是無限的。在這些情況下,我們可以將目標 Vector3 視為相反的方向; 只要 Vector3 指向同一方向,相對於起始 Vector3,負向運動應該表現正常。

以下指令碼使用 MoveTowards 使用平滑距離將一組物件移向一組位置。

using UnityEngine;
    
public class MoveTowardsExample : MonoBehaviour
{
    /// <summary>The red cube will move up, the blue cube will move down, 
    /// the green cube will move left and the yellow cube will move right.
    /// These objects will be linked via the inspector.</summary>
    public GameObject upCube, downCube, leftCube, rightCube;
    /// <summary>The cubes should move at 1 unit per second.</summary>
    float speed = 1f;

    void Update()
    {
        // We determine our distance by applying a deltaTime scale to our speed.
        float distance = speed * Time.deltaTime;

        // The up cube will move upwards, until it reaches the 
        //position of (Vector3.up * 2), or (0, 2, 0).
        upCube.transform.position 
            = Vector3.MoveTowards(upCube.transform.position, (Vector3.up * 2f), distance);

        // The down cube will move downwards, as it enforces a negative distance..
        downCube.transform.position
            = Vector3.MoveTowards(downCube.transform.position, Vector3.up * 2f, -distance);

        // The right cube will move to the right, indefinetly, as it is constantly updating
        // its target position with a direction based off the current position.
        rightCube.transform.position = Vector3.MoveTowards(rightCube.transform.position, 
            rightCube.transform.position + Vector3.right, distance);

        // The left cube does not need to account for updating its target position, 
        // as it is moving away from the target position, and will never reach it.
        leftCube.transform.position
            = Vector3.MoveTowards(leftCube.transform.position, Vector3.right, -distance);
    }
}

所有立方體從中心向外移動,紅色立方體停在目標目的地。

SmoothDamp

SmoothDamp 視為 MoveTowards 的變體,內建平滑。根據官方文件,此功能最常用於執行平滑的相機跟蹤。

除了起始和目標 Vector3 座標,我們還必須提供一個表示速度的 Vector3,以及表示完成運動所需的大致時間的 float 。與前面的例子不同,我們提供速度作為參考,在內部遞增。重要的是要注意這一點,因為在我們仍然執行該功能時改變功能之外的速度會產生不希望的結果。

除了所需的變數之外,我們還可以提供一個 float 來表示我們物件的最大速度,還有一個 float 來表示自上一次 SmoothDamp 呼叫該物件以來的時間間隔。我們不需要提供這些值; 預設情況下,沒有最大速度,時間間隔將被解釋為 Time.deltaTime。更重要的是,如果你呼叫一個函式 MonoBehaviour.Update() 內每個物件的功能,你應該不會需要宣告的時間間隔。

using UnityEngine;
    
public class SmoothDampMovement : MonoBehaviour
{
    /// <summary>The red cube will imitate the default SmoothDamp function. 
    /// The blue cube will move faster by manipulating the "time gap", while 
    /// the green cube will have an enforced maximum speed. Note that these 
    /// objects have been linked via the inspector.</summary>
    public GameObject smoothObject, fastSmoothObject, cappedSmoothObject;

    /// <summary>We must instantiate the velocities, externally, so they may 
    /// be manipulated from within the function. Note that by making these 
    /// vectors public, they will be automatically instantiated as Vector3.Zero 
    /// through the inspector. This also allows us to view the velocities, 
    /// from the inspector, to observe how they change.</summary>
    public Vector3 regularVelocity, fastVelocity, cappedVelocity;

    /// <summary>Each object should move 10 units along the X-axis.</summary>
    Vector3 regularTarget = new Vector3(10f, 0f);
    Vector3 fastTarget = new Vector3(10f, 1.5f);
    Vector3 cappedTarget = new Vector3(10f, 3f);

    /// <summary>We will give a target time of 5 seconds.</summary>
    float targetTime = 5f;

    void Update()
    {
        // The default SmoothDamp function will give us a general smooth movement.
        smoothObject.transform.position = Vector3.SmoothDamp(smoothObject.transform.position,
            regularTarget, ref regularVelocity, targetTime);

        // Note that a "maxSpeed" outside of reasonable limitations should not have any 
        // effect, while providing a "deltaTime" of 0 tells the function that no time has 
        // passed since the last SmoothDamp call, resulting in no movement, the second time.
        smoothObject.transform.position = Vector3.SmoothDamp(smoothObject.transform.position,
            regularTarget, ref regularVelocity, targetTime, 10f, 0f);

        // Note that "deltaTime" defaults to Time.deltaTime due to an assumption that this 
        // function will be called once per update function. We can call the function 
        // multiple times during an update function, but the function will assume that enough
        // time has passed to continue the same approximate movement. As a result, 
        // this object should reach the target, quicker.
        fastSmoothObject.transform.position = Vector3.SmoothDamp(
            fastSmoothObject.transform.position, fastTarget, ref fastVelocity, targetTime);
        fastSmoothObject.transform.position = Vector3.SmoothDamp(
            fastSmoothObject.transform.position, fastTarget, ref fastVelocity, targetTime);

        // Lastly, note that a "maxSpeed" becomes irrelevant, if the object does not 
        // realistically reach such speeds. Linear speed can be determined as 
        // (Distance / Time), but given the simple fact that we start and end slow, we can 
        // infer that speed will actually be higher, during the middle. As such, we can
        // infer that a value of (Distance / Time) or (10/5) will affect the 
        // function. We will half the "maxSpeed", again, to make it more noticeable.
        cappedSmoothObject.transform.position = Vector3.SmoothDamp(
            cappedSmoothObject.transform.position, 
            cappedTarget, ref cappedVelocity, targetTime, 1f);
    }
}

我們可以通過調整 maxSpeed 和 deltaTime 引數來改變物件到達目標的速度。