Questions about programmatically combining transformations

Godot Version

4.5.1

Question

Hi y’all, I’m new to gd script and godot in general and I’m having some issues with 3D rotation. I took a little video and linked it below for reference. I also included the full script that I’m working with.

What I’m trying to accomplish is basically just rotating a cube as you would expect it to if you were to push against the top edge on any given side, as well as translating the cube a single unit(in this case 2m) in the same time frame.

I started by putting together some enums in order to easily map inputs for the rotate and move function.

On ready I set the basis to the identity basis, and during _physics process I’m handling the input. The if statement boils down to when you press a key rotate and move the appropriate direction.

A couple things are happening that I don’t quite understand.

  1. Why isn’t the if not is_turning: check properly preventing multiple inputs from being registered at once?
  2. I know that repeated transformations can cause the basis to deform and for the angles to get out of sync, but I thought that with orthonormalization and resetting the basis to the identity basis that this could be avoided? Is there something that I’m doing incorrectly?

There is obviously something that I’m missing here any help to identify what that is would be appreciated.

Video

Full Script

extends CharacterBody3D


enum axes {X,Z}
enum directions {FORWARD,BACK,LEFT,RIGHT}
var duration = 0.5
var rot_axis
var rot_dir
var move_axis
var move_dir
var is_turning

func _ready() -> void:
	transform.basis = Basis.IDENTITY


func _physics_process(delta: float) -> void:
	if not is_turning:
		if Input.is_action_just_pressed("rotate_n"):
			rot_axis = axes.X
			move_axis =axes.Z
			rot_dir = directions.BACK
			move_dir = directions.FORWARD
			rotate_and_move(rot_axis, move_axis,rot_dir,move_dir)
		if  Input.is_action_just_pressed("rotate_s"):
			rot_axis = axes.X
			move_axis = axes.Z
			rot_dir = directions.FORWARD
			move_dir =directions.BACK
			rotate_and_move(rot_axis, move_axis,rot_dir,move_dir)
		if Input.is_action_just_pressed("rotate_e"):
			rot_axis = axes.Z
			move_axis =axes.X
			rot_dir = directions.FORWARD
			move_dir = directions.FORWARD
			rotate_and_move(rot_axis, move_axis,rot_dir,move_dir)
		if Input.is_action_just_pressed("rotate_w"):
			rot_axis = axes.Z
			move_axis =axes.X
			rot_dir = directions.BACK
			move_dir = directions.BACK
			rotate_and_move(rot_axis, move_axis,rot_dir,move_dir)

func rotate_and_move(rota_axis, mov_axis, rota_dir, mov_dir):
	is_turning =true
	print("Is Turning: ", is_turning)
	$Pivot/Cube.basis = Basis()
	$Pivot.basis = Basis()
	var rot_axis_map = {0:{0:Vector3.FORWARD, 1:Vector3.BACK}, 1:{0:Vector3.LEFT, 1:Vector3.RIGHT}}
	var move_axis_map = {0:{0:Vector3.FORWARD, 1:Vector3.BACK}, 1:{0:Vector3.LEFT, 1:Vector3.RIGHT}}
	var tween = get_tree().create_tween()
	tween.set_parallel(true)
	tween.tween_property($Pivot/Cube, "transform", $Pivot/Cube.transform.rotated_local(rot_axis_map[rota_axis][rota_dir], deg_to_rad(90)), duration)
	tween.tween_property($Pivot, "transform", $Pivot.transform.translated(move_axis_map[mov_axis][mov_dir]*2),duration)
	await get_tree().create_timer(duration).timeout
	is_turning =false
	print("Is Turning: ", is_turning)

			move_axis = axes.Z
			rot_dir = directions.FORWARD
			move_dir =directions.BACK
			rotate_and_move(rot_axis, move_axis,rot_dir,move_dir)
		elif Input.is_action_pressed("rotate_e"):
			is_turning = true
			rot_axis = axes.Z
			move_axis =axes.X
			rot_dir = directions.FORWARD
			move_dir = directions.FORWARD
			rotate_and_move(rot_axis, move_axis,rot_dir,move_dir)
		elif Input.is_action_pressed("rotate_w"):
			is_turning = true
			rot_axis = axes.Z
			move_axis =axes.X
			rot_dir = directions.BACK
			move_dir = directions.BACK
			rotate_and_move(rot_axis, move_axis,rot_dir,move_dir)

func rotate_and_move(rot_axis, move_axis, rot_dir, mov_dir):
	$Pivot.basis = Basis()
	self.basis = Basis()
	var rot_axis_map = {0:{0:Vector3.FORWARD, 1:Vector3.BACK}, 1:{0:Vector3.LEFT, 1:Vector3.RIGHT}}
	var move_axis_map = {0:{0:Vector3.FORWARD, 1:Vector3.BACK}, 1:{0:Vector3.LEFT, 1:Vector3.RIGHT}}
	var tween = get_tree().create_tween()
	tween.set_parallel(true)
	tween.tween_property($Pivot, "transform", $Pivot.transform.rotated_local(rot_axis_map[rot_axis][rot_dir], PI/2), 0.5)
	tween.tween_property(self, "transform", self.transform.translated(move_axis_map[move_axis][move_dir]*2),0.5)
	$Pivot.transform.orthonormalized()
	self.transform.orthonormalized()

Where do you reset is_turning flag?

Put print statements all over your code to check what gets executed and when.

Btw orthonormalized() does not work in-place. It returns the basis/transform. You need to re-assign. Otherwise the call will have no effect.

1 Like