class_name RollingCube extends Node3D @export var _cube_size:= 1.0 @export var _duration = 0.5 @export var _roll_delay = 0.0 @export var _process_mode: Tween.TweenProcessMode @export var _ease: Tween.EaseType @export var _transition: Tween.TransitionType var _rolling:= false ## Rolls the cube along the roll_dir, using the roll_axis as rotation axis. func roll(roll_dir: Vector3, roll_axis: Vector3): if _rolling: return _rolling = true var up_axis = roll_dir.cross(roll_axis) var end_basis:= basis.rotated(roll_axis, deg_to_rad(90)) var tween = create_tween().set_parallel().set_ease(_ease).set_trans(_transition).set_process_mode(_process_mode) tween.tween_method(_roll_translation.bind(position, roll_dir, up_axis), 0.0, 1.0, _duration).set_delay(_roll_delay) tween.tween_method(_roll_rotation.bind(basis, end_basis), 0.0, 1.0, _duration).set_delay(_roll_delay) await tween.finished _rolling = false func _roll_rotation(t: float, start_basis: Basis, end_basis: Basis) -> void: # A basis rotation as shown in the documentation of slerp basis = start_basis.slerp(end_basis, t) func _roll_translation(t: float, start_pos: Vector3, dir: Vector3, up: Vector3) -> void: # The displacement is governed by the arc the center makes as we rotate around the pivot var arc_radius = _cube_size / sqrt(2.0) # Distance from pivot to center of cube var phi = lerp(.25, .75, t) * PI # As we move the center, the arc goes from PI/4 till PI*3/4 var start_offset = 1 / sqrt(2.0) # The start of the arc should be 0, so we need to remove cos(pi/4) and sin(pi/4) which both are 1/sqrt(2) position = start_pos - dir * arc_radius * (cos(phi) - start_offset) + up * arc_radius * (sin(phi) - start_offset)
or share this direct link: