0 votes

I've gotten look_at() working with the mouse successfully, so that the node rotates towards the mouse cursor, using this (basically from the Godot tutorials):

look_at(get_local_mouse_position())

Also I see how you can set rotation directly:

rotation = position.angle_to_point(toplvl_canvas.get_local_mouse_position())

What I can't for the life of me figure out is how to have different rotation rates than just the immediate snap to angle that look_at gives you. What I have so far is something like this:

var rot_speed = 0.02

steering_angle = position.angle_to_point(get_local_mouse_position()) - PI/2
if steering_angle - rotation < 0.1:
    rotation -= rot_speed
elif steering_angle - rotation > 0.1:
    rotation += rot_speed

Which doesn't work when you cross from a small positive angle to -2PI, the zero crossing. It will find the difference to suddenly be the total angle in the other direction of rotation and loop around. I feel like this is something that many people must have implemented, but I haven't been able to figure it out. Is there something obvious I'm missing?

in Engine by (21 points)

1 Answer

+1 vote
Best answer

When this happens to me I make myself a little function that adjusts one of the values so that the angle never crosses the 0 — 2PI boundary, and then uses the built-in lerp() function. Other engines, like unity have a lerp_angle() function built-in. Maybe it should be added to Godot too?

func lerp_angle(a, b, t): #In radians
    if abs(a-b) >= PI: 
        if a > b:
            b += 2 * PI
        else:
            a += 2 * PI
    return lerp(a, b, t)

EDIT: I didn't read the question that well. If you want to rotate at a set speed, use these:

func rotate_const_speed(a, b, d): #In radians
    if abs(a-b) >= PI: #only need to adjust for the long way round
        if a > b:
            b += 2 * PI
        else:
            a += 2 * PI
    return move_towards_float(a, b, d)

func move_towards_float (x, target, step): #Moves towards t without passing it
    if abs(target - x) < abs(step):
        return target
    else: return x + step
by (108 points)
selected by

Thanks so much! I couldn't make this work in my head, and this was exactly what I was trying to build. I made one slight modification (probably obvious) to handle step direction, as I believe you would have to make that determination after adding 2PI.

func rotate_const_speed(a, b, d): #In radians
    if abs(a-b) >= PI: #only need to adjust for the long way round
        if a > b:
            b += 2 * PI
        else:
            a += 2 * PI
    if a > b:
        d = -d
    return move_towards_float(a, b, d)

func move_towards_float (x, target, step): #Moves towards t without passing it
    if abs(target - x) < abs(step):
        return target
    else: return x + step
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.