This article is also available on Odysee.
rotation_degrees, transform.basis and quaternions
If you want to rotate a character towards a point, there are three popular methods you can use: modifying the character’s rotation_degrees.y value, changing the transform.basis or using quaternions. This tutorial will show you how the transform.basis approach works.
The transform.basis property of any Spatial node (or nodes that inherit from Spatial, like KinematicBody) consists of 9 values that represent the node’s rotation and scaling. You can read more about this in Godot’s official documentation about transforms.
Let’s start with a short explanation of what the code is meant to do, this makes it easier to understand. We want the character to turn towards a certain point whenever we hand him new coordinates. The character will need to figure out which direction this point is in relation to his current position and then start rotating to face the new point. Rotating is done by gradually changing the current rotation to the desired rotation.
Rotating by using transform_basis
We’ll now look at the code. For this tutorial we’ll use a KinematicBody as the main node for our character. We need four variables:
extends KinematicBody var target_location: Vector3 var target_rotation: Basis var rotation_lerp:= 0.0 var rotation_speed:= 1.0
- The target_location is the point in world coordinates we want the character to face
- The target_rotation is the new basis that the character should use for his rotation
- The rotation_lerp ranges from 0 to 1 and will be used to interpolate the character’s rotation from his current rotation to the desired rotation
- The rotation_speed is a multiplier that can be used to change how fast the character turns.
func set_target_location(new_target: Vector3): target_location = new_target rotation_lerp = 0
Whenever we want the character to face a new position, we call set_target_location() and enter a Vector3 as an argument. We also reset the rotation_lerp to 0, because the character will have to start rotating to a new direction.
func rotate_player(delta): if rotation_lerp < 1: rotation_lerp += delta * rotation_speed elif rotation_lerp > 1: rotation_lerp = 1 transform.basis = transform.basis.slerp(target_rotation, rotation_lerp).orthonormalized()
The rotate_player function is executed every frame. It increments the rotation_lerp value until the value has reached 1. We modify this transform by using the slerp function (slerp stands for spherical linear interpolation). The slerp function blends the character’s rotation from its current value to the target_rotation. We then use .orthonormalized() to make sure the basis does not deform after a while.
target_location.y = transform.origin.y
if target_location != transform.origin:
target_rotation = transform.looking_at(target_location, Vector3.UP).basis
We set the target_location’s height to the same height as the character’s origin. This keeps the character from tilting up or down if the target is not on the same height as the character. Remove this line of code for characters that should tilt, like space ships, planes, divers or turret cannons. I’ve modified this part slightly in the sample scene that you can download at the bottom; you can toggle the behavior on and off with a button in the UI.
We then check if the target_location is not the same as the character’s current location. This avoids an error message as well as unreliable behavior. If they aren’t the same, we use the looking_at function on the character’s transform. This functions returns what the character’s rotation would be if he’d face the target_location, without actually rotating him. Lastly we call the rotate_player() function that we implemented in the previous paragraph.
You can download the sample scene shown in the GIF at the top on Gitlab. It contains a bit more code than this tutorial and shows a character that rotates to a new target every two seconds.