Smoothly rotate towards question

Godot Version

4.7

Question

Hi, I’m trying to make a topdown game, and I am to rotate my character towards my mouse cursor.

var use = %Camera3D.project_position(get_viewport().get_mouse_position(),-6.9)
%MeshInstance3D.look_at(use)
	

Right now this code is perfectly snapping towards my cursor, is there a way to lerp towards it instead?

I tested this in Godot 4.7.1. look_at() applies the rotation immediately. Since a top-down character usually only rotates around the Y axis, you can interpolate the yaw with lerp_angle():

@export var turn_speed := 8.0

func _process(delta: float) -> void:
    var mesh := %MeshInstance3D
    var target := %Camera3D.project_position(
        get_viewport().get_mouse_position(),
        6.9
    )

    var direction := target - mesh.global_position
    if is_zero_approx(direction.x) and is_zero_approx(direction.z):
        return

    # Godot's default forward direction is -Z.
    var target_yaw := atan2(-direction.x, -direction.z)

    # This stays between 0 and 1, even during a long frame.
    var weight := 1.0 - exp(-turn_speed * delta)

    var new_rotation := mesh.global_rotation
    new_rotation.y = lerp_angle(new_rotation.y, target_yaw, weight)
    mesh.global_rotation = new_rotation

Adjust turn_speed to control the response. If the model faces +Z instead of Godot’s default -Z, add PI to target_yaw.

Also, project_position() defines z_depth as a distance into the scene, so it should normally be positive. With a straight-down camera 6.9 units above the ground, 6.9 reaches the ground plane while -6.9 projects behind the camera.

You can take a look at the working demo here:

Thank you for this. I was wondering what the if statement was doing. I was also wondering if there was a way to prevent the rotation slowing down as you reach the target value. I tried move_toward, but as I moved my mouse to the lower half of the screen near the middle, the mesh would rotate the other way to reach my target point. Again, thank you so much for this,

You can use rotate_toward instead of move_toward which wraps around TAU

I might have misunderstood the question completely :sweat_smile: :rofl:
Glad there is a solution already!