首页 > 解决方案 > Unity Lerp in seconds - 点列表

问题描述

我有一个带有时间框架的游戏对象的翻译和旋转列表。

示例(翻译):

Point 1: (X1, Y1, Z1) Current Time T1 
Point 2: (X2, Y2, Z2) Current Time T2 
Point 3: (X3, Y3, Z3) Current Time T3

...

在这种情况下,我需要一个与 Lerp 从点 1 到 2 的协程,时间为 (T2-T1) 秒。之后,从第 2 点到第 3 点,用 T3-T2 秒……关键是,每个动作都应该等待前一个动作的完成。点之间的增量时间大约为 0.1 秒。

我该怎么做?此外,我还有类似于平移的旋转 (Rx1-n,Ry1-n,Rz1-n)。

标签: c#unity3d

解决方案


移动可以在一个简单的协程中完成,比如

// Moves a given object from A to B within given duration
IEnumerator MoveWithinSeconds(Transform obj, Vector3 from, Vector3 to, float duration)
{
    var timePassed = 0f;
    while(timePassed < duration)
    {
        // will always be a factor between 0 and 1
        var factor = timePassed / duration;
        // optional ease-in and ease-out
        // factor = Mathf.SmoothStep(0,1,factor);

        // linear interpolate the position
        obj.position = Vector3.Lerp(from, to, factor);

        // increase timePassed by time since last frame
        // using Min to avoid overshooting
        timePassed += Mathf.Min(Time.deltaTime, duration - timePassed);

        // "pause" the routine here, render the frame
        // and continue from here in the next one
        yield return null;
    }

    // just to be sure apply the target position in the end
    obj.position = target;
}

然后简单地从另一个协程迭代你的元素,比如

// the object you want to move
public Transform obj;
// your waypoints class with position and time stamp
public List<WAYPOINT>() waypoints;

IEnumerator MovementRoutine()
{
    // if 0 or only 1 waypoint then it makes no sense to go on
    if(waypoints.Count <= 1) yield break;

    // pick the first item
    var fromPoint = waypoints[0];
    // since you already have the first start the iteration with the second item
    for(var i = 1; i < waypoints.Count; i++)
    {
        var toPoint = waypoints[i];
        var fromPosition = fromPoint.position;
        var toPosition = toPoint.position;
        var duration = toPoint.time - fromPoint.time;

        // this executes and at the same time waits(yields) until the MoveWithinSeconds routine finished
        yield return MoveWithinSeconds(obj, fromPosition, toPosition, duration);

        // update fromPoint for the next step
        fromPoint = toPoint;
    }
}

旋转也可以这样做。但是请注意,在某些情况下,仅通过 XYZ 在欧拉空间中旋转有点棘手。您可能更应该将四元数与 XYZW 一起存储和使用。


注意:只要您的帧速率足够高/增量时间足够大,这将运行良好。问题在于yield return将以下代码至少推迟 1 帧。因此,在增量时间变得小于帧速率的情况下,它将无法按预期工作。


推荐阅读