I need to linearly interpolate more linearly.

Hi. So, I have the following code:

using UnityEngine;
using System.Collections;

public class BotController : MonoBehaviour {

    public int framesPerCycle;

    int cycles;
    int frames;
   
    Vector3 wantedPos;

    void Start () {
    }
   
    void Update () {
        frames++;

        if (frames >= framesPerCycle) {
            cycles++;
            frames = 0;
            wantedPos = transform.position + transform.forward;
        }

        transform.position = Vector3.Lerp(transform.position, wantedPos, Time.deltaTime);
    }
}

And, the idea is that I can choose a number of frames per cycle, and every cycle, the player is supposed to move forward one block. I didn’t want this to be an instant teleportation, so I lerp’d between the two positions. I noticed very quickly, that, for example, lerping between 100 and 1 at 50% is not the same as lerping between 5 and 1 at 50%. What this meant was that, as the player got closer to the WantedPos, they would slow down, and usually never even reach the wantedPos before the next cycle began, resulting in a somewhat choppy non-linear motion. Can someone help?

1 Like
1 Like

its because of several reasons.

you are using frame dependent calculations. a frame isn’t always going to take the same amount of time each second, at one point you may have 60 frames per second and another 15, and then later you get 200 frames per second. its highly variable.

Also I think its important for you to also take some time to learn exactly what Lerp is doing and what happens when you feed specific values that you are giving it. you’re using :

transform.position = Vector3.Lerp(transform.position, wantedPos, Time.deltaTime);

Time.deltaTime gives you how much time has passed this frame. lets assume a fixed time of 1 seconds/60 frames = 0.01666 seconds this frame. lerp will practically see that as a percent, or 1.66%. in other words your telling it to find the point that is 1.66% from my current position to my target position.

if you were 1000 units away then you will have moved 16 units closer to the target. however you always using from your current position in the math which means as time passes you will go slower the closer you get to the target. At 10 units away you’d only move 0.16 units.

Instead track the amount of seconds that have passed and use that value as the 3rd variable in the Lerp.

or to make it really simple just use MoveTowards.

float timer=0;

void Update()
{
    timer += Time.deltaTime;

    if (timer>= secondsPerCycle)
    {
        cycles++;
        timer= 0;
        wantedPos = transform.position + transform.forward;
    }

    transform.position =Vector3.MoveTowards(transform.position, wantedPos, speedPerSecond * Time.deltaTime);
}

Another option is to use something like LeanTween which has two advantages: more readable code and easier maintenance.

LeanTween can allow you specify the ‘ease’ technique such as Linear, Sine, Quad, etc. You can even specify your own via an animation curve.

LeanTween is free and is available in the asset store: Unity Asset Store - The Best Assets for Game Making

For example to do what you’re doing here is a one liner like:

LeanTween.move(gameObject, wantedPos, duration);

Another package for tweening, see DOTween. I like it a lot.

also,
simple single class easing functions for Unity
https://github.com/mimicteam/easing-for-unity

2 Likes

I choose LeanTween due to: http://dentedpixel.com/video/leantween-speed-comparison-to-itween-and-hotween/

The Unity built-in MoveTowards is good for mostly constant motion. I’ve got a long explanation and example in Vector math and rotation notes. In part 6 (moving points and rotations,) section 1.1. It shows the tweak to slow down where you’re almost there.

The way you’re using lerp is deliberately meant to be very, very non-linear (yes, long explanation, and both kinds of lerp usage, is in section 1.2 of same.)

My TLDR is:

t += Time.deltaTime;
x = Mathf.Lerp(a, b, t);

= Linear Lerp. For a slow down near the end, change the lerp function, not what is passed in.

1 Like