help with float lerp

i am trying to lerp between 2 float values with a smooth start and a smooth end, i have tried mathf.lerp and smoothstep, smoothstep seems to start off faster and then go really slow at the end and mathf lerp also only seems to slow at the end and not gradually speed up at the start

grateful for any help

can you show your code?

can also use animation curve to manually create suitable curve if thats the issue:

or these
Robert Penner's easing equations for Unity · GitHub (from Easing Functions Cheat Sheet )

are you working with quaternions or with positions?
because you can’t work with quaternions like that.

lerp will linearly transition from start to end
smoothstep will do this instead

make sure your t is in range 0.0 to 1.0

here is code thanks, can not get smooth at start and end

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MATHFLERPTEST1 : MonoBehaviour {


public float speed = 2;

public float score = 0f;
public float scoreTo = 100f;


    void Start () {
       
    }


   
   
    void Update () {



        score = Mathf.SmoothStep(score, scoreTo, Time.deltaTime*speed);




     Debug.Log("Value " + score);


    }
}

You cannot use Time.deltaTime in a lerp.
You’re mixing units [frame/second] with something that is essentially just a unitless ratio (%).

You need to convert/rephrase your lerp into units that are bound to time and work with that.
The easiest way to achieve this would be to define what is the absolute time interval you’re working with.

Let’s say totalTime is 2 seconds.
Then you get your unitless ratio if you get your currentTime / totalTime, and synchronize some other value against this.

// public and settable from inspector
public float startScore = 0f;
public float endScore = 100f;

// settable from inspector
[SerializeField] [Range(0.001f, 5f)] float totalLerpTime = 2f;
[SerializeField] bool animate = false;

// private
float _currentTime = 0f;

void Update() {
  if(animate) {
    float ratio = Mathf.Min(1f, _currentTime / totalLerpTime);
    score = Mathf.SmoothStep(startScore, endScore, ratio);
    Debug.Log(score);
    animate = ratio < 1f;
    if(animate) _currentTime += Time.deltaTime;
  }
}

// usable from inspector
public void Reset() {
  _currentTime = 0f;
  animate = false;
}

// usable from code
public void Run(float time) {
  Reset();
  totalLerpTime = time;
  animate = true;
}

Alternative way, if you’re not sure what’s what

void Update() {

  if(animate) { // process the passage of time

    // compute the ratio
    var ratio = _currentTime / totalLerpTime;

    // check the ratio (we don't want to overshoot 100%)
    if(ratio > 1f) ratio = 1f;

    // actual job (syncing and interpolating the other value)
    score = Mathf.SmoothStep(startScore, endScore, ratio);
    Debug.Log(score);

    // getting ready for the next step
    if(ratio < 1f) { // we're not there yet
      _currentTime += Time.deltaTime;
    } else { // we're there
      animate = false;
    }

  }

}

If you want to work with speed instead, you just have to calculate totalLerpTime from this.
If velocity V = st then t = V/s , so

oops, got that swapped
If velocity V = s/t then t = s/V , so

totalLerpTime = Mathf.Abs(endScore - startScore) / speed;

I.e.

public void RunFor(float time) {
  Reset();
  totalLerpTime = time;
  animate = true;
}

public void RunAtSpeed(float speed) {
  RunFor(Mathf.Abs(endScore - startScore) / speed);
}

Use slerp. It’s spherical interpolation instead of linear.
Or download a free copy of Lean-tween on the asset store. It’s absolutely genius.

Thanks for all the replies, i am sure i can get it working now i have all the helpfull stuff above, thanks again

1 Like

i am using the orionsyndrome script but there still dont seem to be much smoothing at start and end, it only seems to start to slowdon when the score reaches 99 can it be made to gradually speed upto about a quarter then slow down in the last quarter

you can use AnimationCurve if you don’t like what you’re getting with SmoothStep

// public and settable from inspector
public float startScore = 0f;
public float endScore = 100f;

// settable from inspector
[SerializeField] AnimationCurve curve; // tweak this in the inspector
[SerializeField] [Range(0.001f, 5f)] float totalLerpTime = 2f;
[SerializeField] bool animate = false;

// private
float _currentTime = 0f;

void Update() {
  if(animate) {
    float ratio = Mathf.Min(1f, _currentTime / totalLerpTime);
    score = Mathf.Lerp(startScore, endScore, curve.Evaluate(ratio));
    Debug.Log(score);
    animate = ratio < 1f;
    if(animate) _currentTime += Time.deltaTime;
  }
}

// usable from inspector
public void Reset() {
  _currentTime = 0f;
  animate = false;
}

// usable from code
public void RunFor(float time) {
  Reset();
  totalLerpTime = time;
  animate = true;
}

// speed is assumed as uniform throughout
// in order to compute the total duration
public void RunAtSpeed(float speed) {
  RunFor(Mathf.Abs(endScore - startScore) / speed);
}

In general, animation tweening is a large topic, I could also give you many functions to customize this behavior to your heart’s content, but this would (probably) only confuse you, and it all boils down to only two things anyway, using AnimationCurve to manually draw the desired slowdowns and speedups, or getting a fully-featured tweening library as recommended before by mgear and Alvarezmd90

Also depending how many of these you wish to run at the same time, I’d propose setting enabled to false, instead of using animate variable. This is a better way of ensuring Update won’t be called at all, if it’s not needed.

I.e.

public class MyTweeningTest : MonoBehaviour {

  public float startScore = 0f;
  public float endScore = 100f;

  // private but inspectable
  [SerializeField] AnimationCurve curve;
  [SerializeField] [Range(0.001f, 5f)] float totalTime = 2f;

  // private
  float _time = 0f;
 
  void Awake() {
    Reset();
  }

  void Update() {
    float ratio = Mathf.Min(1f, _time / totalTime);
    float score = Mathf.Lerp(startScore, endScore, curve.Evaluate(ratio));
    Debug.Log(score);
    enabled = ratio < 1f;
    if(enabled) _time += Time.deltaTime;
  }

  // usable from inspector
  public void Reset() {
    _time = 0f;
    enabled = false;
  }

  // usable from code
  public void RunFor(float time) {
    Reset();
    totalTime = time;
    enabled = true;
  }

  public void RunAtSpeed(float speed) {
    RunFor(Mathf.Abs(endScore - startScore) / speed);
  }

}

I have a small problem now, i have the following code that when run in update is fine but i will need to use it in a function so i need a while loop, but it is making unity freeze, can anyone show me the right way to use the while loop with the code i have below, thank you

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ANIMATIONCURVE17 : MonoBehaviour {







    private static float score;
    private static float scoreStart = 0f;
    private static float scoreEnd = 50f;


    [SerializeField] AnimationCurve curve;
    [SerializeField] [Range(0.001f, 50f)] float totalLerpTime = 20f;

    private bool animate = true;
    
    // private
    float _currentTime = 0f;


    void Start(){
    Runner();
    }

//     void Update() {

         void Runner() {


    //    if(score !=scoreEnd) {

            while(score !=scoreEnd) {

            float ratio = Mathf.Min(1f, _currentTime / totalLerpTime);

                score = Mathf.Lerp(scoreStart, scoreEnd, curve.Evaluate(ratio));

                Debug.Log(" SCORE  " + score);

            animate = ratio < 1f;

        if(animate) _currentTime += Time.deltaTime;

   
        }
        return;
    }
}

The ‘return’… is it inside the while loop? It doesn’t seem to be the case as far as I can tell.
You ALWAYS require to break out of a loop, otherwise crashes will occur 100%.

if i move it into the bottom of the loop , the lerp wont run, this is why i need help, i just cant seem to get it right

Then you have to create a for loop to go through until the lerp is done.

for (float t = 0.0f; t < 1.0f; t += Time.deltaTime / aTime)
{
     ValueToChange = Mathf.Lerp(OldValue, TargetValue, t)
}

@Alvarezmd901 I’m positive he doesn’t want to do that.

Why do you need while @melonhead ?
Wasn’t the solution good enough the way it was?
If not, you should ask about the thing that bothers you.

Thankfully I was the creator of the script, so it’s better to go to the root of the problem.

Ah you basically switched Update into your own function. Well, you can’t do that.
You see, Unity will internally call Update each frame, and this is how that script of mine works. You can’t do that with your own functions.

Well you can, but you’d still end up calling them from within Update, it’s the main thing that gets called from the underlying Unity engine, and the only reliable way to update your game in sync with the engine itself.

The question is what about Update you find non-intuitive so that you have to call your own method ‘Runner’ from Start?