Rotate KinematicBody2D based off mouse position with varying rate

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By skippydog

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?

:bust_in_silhouette: Reply From: camarones

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

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

skippydog | 2018-05-23 00:11