简体   繁体   中英

Unity Lerp in Seconds - List of Points

I have list of translations and rotations for a gameobject with timeframe.

Example (translation):

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

...

In this case, I need a coroutine with Lerp from Point 1 to 2 with (T2-T1) seconds. After, from Point 2 to 3 with T3-T2 seconds... The point is, each movement should wait the completion of previous one. The delta time between points is roughly 0.1 seconds.

How should I do it? In addition, I also have the rotations (Rx1-n,Ry1-n,Rz1-n) similar to translations.

The movement can be done in a simple Coroutine like

// 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;
}

and then simply iterate your elements from another Coroutine like

// 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;
    }
}

Same can be done for rotations. Note however that rotating in eulerspace by only XYZ is a bit tricky in some conditions. You should probably rather store and use Quaternion with XYZW.


Note: This will work well as long as your frame-rate is high enough / the delta time big enough. The problem is that yield return postpones the following code at least 1 frame. So in cases where the delta time becomes smaller then the frame-rate it will not work as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM