+4 votes

Is there a GDScript function to lerp between two angles?
For example, make it so 270° => 20° doesn't go backwards.

in Engine by (28,789 points)
edited by

5 Answers

–3 votes

One possible solution is to convert angle to float and lerp with the float, then convert to back to angle and use it.

by (683 points)

What do you mean by angle? My angle is already a float variable.

0 votes

Take normalized directional vectors for angles.
A vector 1,0 will be 0 deg, vector 0,1 will be 90deg.

Then lerp between these vectors and find the angle of the resulting vector.

There are easier solutions for this if you manually calculate the angle instead of lerping. Or if you want to lerp the rotation of something, there is quaternion slerp in gdscript.

by (750 points)

I actually compute the angle myself, and it's 2D so I don't use quaternions. Converting back and forth in vectors could work but I'm sure there is a faster way.

+8 votes

I found a solution:

static func lerp_angle(a, b, t):
    if abs(a-b) >= PI:
        if a > b:
            a = normalize_angle(a) - 2.0 * PI
            b = normalize_angle(b) - 2.0 * PI
    return lerp(a, b, t)

static func normalize_angle(x):
    return fposmod(x + PI, 2.0*PI) - PI

You can add it to your helpers :p

An example project:

by (28,789 points)

Thank you! I've been trying to figure this out for a while.

+5 votes

EDIT: Godot now has a lerp_angle function.

Zylann's solution doesn't seem to work when there's an offset before the lerping:

func _process(delta):
    var to_mouse = $Sprite.global_position - get_global_mouse_position()
    var offset = -PI / 2
    var rotation_to_mouse = to_mouse.angle() + offset
    $Sprite.rotation = lerp_angle($Sprite.rotation, rotation_to_mouse, 0.25)

So this is an alternative which works in that case
adapted from https://gist.github.com/shaunlebron/8832585:

func lerp_angle(from, to, weight):
    return from + short_angle_dist(from, to) * weight

func short_angle_dist(from, to):
    var max_angle = PI * 2
    var difference = fmod(to - from, max_angle)
    return fmod(2 * difference, max_angle) - difference
by (4,163 points)
edited by

thanks, man. it works!

0 votes

You can use wrapf, wrap the difference in -PI to PI

func lerp_angle(from, to, weight):
    var diff = wrapf(to - from, -PI, PI)
    var i = lerp(from, from + diff, weight)
    # Keep the result in 0..2*PI
    i = wrapf(i, 0, 2*PI)
    return i

func _ready():
    for i in range(0, 10):
        print(rad2deg(lerp_angle(deg2rad(270), deg2rad(20), i/10.0)))
by (20 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.