Rotate smoothly with look_at

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

Hey. I am moving and rotating my Player with the following lines:

func physics_process(delta):
	player.motion = player.position.direction_to(player.get_global_mouse_position()) * 600

The look_at method makes it turn almost instantly. I want to make that more smooth. Can anyone help me with this please? (Maybe with a Tween?)


Edit: If you’re wondering why I am using a reference to the player and why I don’t use _physics_process(delta). This script is from a subclass of a State machine which controls Player movement. The actual _physics_process method is in the Base Class.

:bust_in_silhouette: Reply From: Samomba

I am currently looking for the same thing.

After searching the web this code was pointed to me as a possible solution, but I am not very familiar with tweens. This code is also really fast and I can’t seem to make it turn slower.

Hope it helps anyway.

extends Node2D

onready var TweenNode = get_node(“Tween”)

func _process(delta):

# target to look at
var target = get_global_mouse_position()

# initial and final x-vector of basis
var initial_transform_x = self.transform.x
var final_transform_x = (target - self.global_position).normalized()

# interpolate
TweenNode.interpolate_method(self, '_set_rotation', initial_transform_x, final_transform_x, 0.1, Tween.TRANS_LINEAR, Tween.EASE_OUT)

apply rotation

func _set_rotation(new_transform):

# apply tweened x-vector of basis
self.transform.x = new_transform

# make x and y orthogonal and normalized
self.transform = self.transform.orthonormalized()
:bust_in_silhouette: Reply From: Andrea

look_at is not the function you need, you need looking_at, which creates a new transform.
i basically create a new transform that look at the target, and then i used lerp to interpolate the x,y,z basis of the camera transform with the one of the created transform

func _process(delta):  #inside camera process
		var T=global_transform.looking_at(target.global_transform.origin, Vector3(0,1,0))
		global_transform.basis.y=lerp(global_transform.basis.y, T.basis.y, delta*camera_speed)
		global_transform.basis.x=lerp(global_transform.basis.x, T.basis.x, delta*camera_speed)
		global_transform.basis.z=lerp(global_transform.basis.z, T.basis.z, delta*camera_speed)

I previously commented that this works perfectly but actually it doesn’t. It works in one direction but it scales the model in a negative direction sometimes. Especially if it is a 180 degree turn.

Dileeep | 2022-10-17 03:41

You are right, above solution does not work with 180° turn.
Rotation happens when at least 1 basis vector changes direction (the others follow automatically using an orthonormalization process), but in case of a 180° turn, you are just changing the magnitude of one of the vectors and keep the other 2 as the same. Therefore the lerping just shrink the part and then it flips it.

I suggest to add a line of “if” code to intercept those situation, and rotate the part toward a 90° direction first, before continuing toward the 180° one

Andrea | 2022-10-17 21:17

:bust_in_silhouette: Reply From: Afely

This solution definitely isn’t the best, but it’s very simple and easy to grasp, so this is how I do it:

var weight = 0.1

func physics_process(delta):
    player.motion = player.position.direction_to(player.get_global_mouse_position()) * 600

    player.rotation = lerp_angle(player.rotation, (player.get_global_mouse_position() - player.global_position).normalized().angle(), weight)
:bust_in_silhouette: Reply From: jeudyx

This is the right solution:

(sample code 3d Rotate Direct Constant Smooth - Godot Asset Library)

I tried it and works perfectly.

1 Like

This definitely works, but when applied to a 3d character, it causes them to “bob” up and down as they change direction, even between say, 90 and 105 degrees.

Not sure if it’s due to the way the character is changing direction or some kind of animation reset.

The key line in the above solution (called ‘smooth’) is this one, in the _physics_process, in my case for a 3D character looking in a direction (Vector3):

rotation.y = lerp_angle( rotation.y, atan2( -direction.x, -direction.z ), delta * SMOOTH_SPEED ) # SMOOTH_SPEED being a float, e.g. 10.0

Although the atan2 looks a bit cumbersome, this one line really solved the puzzle for me!!