Lerp weight value question

Godot Version

v4.4.1

Question

I’m having trouble with lerping an int value, it’s giving an unexpected outcome.
I’m lerping both a health and energy variable for the characters in my game, the health works fine but the energy doesn’t, and both variables are using the exact same code.

I setup a test where every time I press space bar it takes 100 health and gives 50 energy, unless energy is at or over 100, in which case it depletes the energy to 0. Here’s the code:

But for some reason, the health works completely fine, but the first time the energy only goes to 31 instead of 50, but if I press space again, it does actually increase by 50 (giving a value of 81). Here’s a screenshot:

Changing the “weight” parameter on the lerp function changes the “31” value, changing the weight to 1 does actually give 50 energy on the first round, but instantly snaps the value (the lerp is basically instant, instead of a smooth transition).

Can someone help explain the “weight” parameter of the lerp function to me and why my lerp isn’t going all the way to 50 on the first round?

Thank you.

The health doesn’t work properly either. health is constantly getting closer to new_health but it never reaches it, and energy is stuck at 31 because of a type conversion from float to int.

I suggest changing the values for health and energy instantly, and then you can use Tweens to animate the progress bars.

Ah yes I see, you are right. If I convert both variables to floats they behave the same (energy does go to 50 on the first time). But I can see it continually increases at extremely small increments as it starts to reach the destination value. Which means it’s not very effective code in this instance.

Thank you for the advice, I’ll rewrite it to use Tweens instead of lerp.

Thanks again!

I am going to once again pull out my axe and grind it. This isn’t how you use lerp().

The last parameter of lerp() is a time value between 0.0 and 1.0. If you want to actually Linearly Interpolate (which is what “lerp” is short for), you need to use fixed values for the first two parameters and a varying value for the last.

Using a fixed time value with varying endpoints gives you logarithmic interpolation, which is rarely what you want.

What you probably want is something like:

const INTERP_TIME: float = 2.0 # 2 seconds...

var old_health:  float # What health was before.
var new_health:  float # What health will be.
var health_time: float # How much time is left to interpolate.
var health:      float # Current health value.


func _process(delta: float) -> void:
    if health_time >= 0.0:
        health_time = clampf(health_time - delta, 0.0, INTERP_TIME)
        # NOTE: health_time counts _down_ so we flip old/new in the lerp().
        health = lerp(new_health, old_health, health_time / INTERP_TIME)


func change_health(amt: float) -> void:
    if !is_zero_approx(health_time): # Are we mid-interpolation?
        new_health += amt # Change the target endpoint.
    else:
        old_health = health       # Set up a new interpolation.
        new_health = health + amt

    health_time = INTERP_TIME # Set the timer.

Edit: Wrong max argument to the clamp.

3 Likes

If I understand correctly, your health has a higher max value, hence it can properly increase without dropping the decimal places. But your energy is operating on lower values, in which case 0.05 is too low to even have the integer increase by 1, hence every frame it keeps evaluating to the same value.

Eg:

  • 0 → 100 with a weight of 0.05 will return 5
  • 0 → 50, weight 0.05 will return 2 (2.5 but it got casted to an int)
  • 31 → 50, weight 0.05 will return 31 (31.95)
  • It’s highly likely the closer your health approaches 900 by using only lerp, the health will get stuck at some point due to the same issue for the energy.

My recommendation is to change both energy and health into float values, then when displaying on the UI, cast to int.
Option 2 - Don’t use lerp.
Option 3 (complicated) - create another var for energy_f which is a float, and apply the lerp result on it, then every frame set energy = energy_f. Only when your energy is consumed or increased, set energy_f = energy. Same for health

Thank you for explaining Lerp more thoroughly Hexgrid, I realize now it was the wrong scenario to use Lerp for sure.

And thanks TheSquawkyRaven for your suggestion, you are right, changing the variables to floats did actually Lerp properly, however, I went with Grulps recommendation of Tweens instead of Lerp.

Luckily Tweens are super simple and it just works the way I wanted it too with minimal code.

If this helps anyone else in a similar situation, here’s how I changed my Lerp code to Tween code:


(the set_ease() function is optional too by the way, I just like the look of it)

Thank you all for your help :grinning_face: very lovely community on these forums!

P.S. how do I insert a code block on these comments? I only see Blockquote and Preformatted text

```gdscript
code
```

1 Like