How do I tone down my look_at() func for a interaction system

Godot Version

v4.5.stable.official [876b29033]

Question

Hello I’m trying to make a Amnesia: The Bunker(I’ve never played the dark descent) style interaction system but I’m not sure how to make a look_at() function that can be toned down and have weight.

It’s a little messy but the main part is this in a hand script that handles the forces and looking function. The goal is more weight = less force to the rotation of the object:

extends Node3D

@onready var hand: Marker3D = $Camera3D/Marker3D
@onready var camera_3d: Camera3D = %Camera3D
@export var weapon_sway_amount : float = 5
@export var weapon_rotation_amount : float = 1
@onready var weapon_holder: Node3D = $weapon_holder
var grabbing = false
var target: RigidBody3D = null

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass

# Called every frame. 'delta' is the elapsed time since the previous frame.

func _physics_process(delta: float) -> void:
	if target and grabbing:
		target.look_at(camera_3d.global_position)

func _on_player_apply_force() -> void:
	apply_force()

func _on_player_throw() -> void:
	apply_throw()

func _on_area_3d_body_entered(body: Node3D) -> void:
	if body.is_in_group("object") and grabbing == false:
		target = body

func apply_force():
	if target != null:
		# Define the target position in world space (e.g., in front of camera)
		
		var target_position = hand.global_position
		# Calculate direction vector
		var direction = (target_position - target.global_position)
		
		# Spring strength (higher = stiffer)
		var strength = 20.0 
		var applied_strength = max(0, strength - target.mass)
		
		
		# Apply force toward center
		target.linear_velocity = direction * applied_strength
		
		# Damp velocity to prevent excessive oscillation
		target.linear_velocity *= 0.9 
		target.angular_velocity = Vector3.ZERO

func apply_throw():
	if target != null:
		# Define the target position in world space (e.g., in front of camera)
		
		# Calculate direction vector
		
		# Spring strength (higher = stiffer)
		var strength = 30
		
		var direction = target.global_transform.basis.z
		
		var force_to_apply = max(0, strength / target.mass + 5)
		
		# Apply force toward center
		target.linear_velocity = direction * force_to_apply
		
		
		# Damp velocity to prevent excessive oscillation
		target.linear_velocity *= 0.9 
		target.angular_velocity = Vector3.ZERO

func _on_player_grabbing_false() -> void:
	grabbing = false

func _on_player_grabbing_true() -> void:
	grabbing = true

Maybe you could use Quaternion’s arc_from, arc_to constructor or Basis’s looking_at to form a target rotation, then their slerp between the current quaternion/basis and the new target. Or use get_euler to try and apply an angular_velocity towards the target rotation.

1 Like

Thanks for the suggestion I actually just finished testing it and found a solution: func _physics_process(delta: float) → void:
if target and grabbing:

	var base_rotation_speed := 8.0
	
	var mass : float = max(target.mass, 0.1)
	
	var rotation_weight : float = (base_rotation_speed / mass) * delta
	
	var direction = (camera_3d.global_position - target.global_position).normalized()
	var target_basis = Basis().looking_at(direction, Vector3.UP)

	var current_scale = target.global_transform.basis.get_scale()
	var current_rotation = target.global_transform.basis.orthonormalized()

	var new_rotation = current_rotation.slerp(target_basis, rotation_weight)
	new_rotation = new_rotation.scaled(current_scale)

	target.global_transform.basis = new_rotation
1 Like