extends Interactable class_name SliderInteractable @export var body: RigidBody3D @export var slider_joint: SliderJoint3D @export var springStrength: float = 200.0 @export var springDamping: float = 15.0 @export var maxGrabDistance: float = 4.0 var dragging: bool = false var grabLocal: Vector3 var handOffsetLocal: Vector3 func _ready() -> void: if body: body.mass = max(body.mass, 0.01) await get_tree().physics_frame if slider_joint: var orig_a = slider_joint.node_a var orig_b = slider_joint.node_b slider_joint.node_a = NodePath("") slider_joint.node_b = NodePath("") slider_joint.node_a = orig_a slider_joint.node_b = orig_b func beginInteract(player, hitPosition: Vector3) -> void: dragging = true grabLocal = body.to_local(hitPosition) var holdPoint = player.hand handOffsetLocal = holdPoint.global_basis.inverse() * (hitPosition - holdPoint.global_position) func updateInteract(player) -> void: if !dragging: return body.sleeping = false var worldGrab = body.to_global(grabLocal) if player.global_position.distance_to(worldGrab) > maxGrabDistance: player.stopInteraction() return var holdPoint = player.hand var targetGrabGlobal = holdPoint.global_position + (holdPoint.global_basis * handOffsetLocal) var errorVector = targetGrabGlobal - worldGrab var slide_axis_global = slider_joint.global_basis.x.normalized() var linear_error = errorVector.dot(slide_axis_global) var linear_velocity = body.linear_velocity.dot(slide_axis_global) var force_magnitude = (linear_error * springStrength) - (linear_velocity * springDamping) body.apply_central_force(slide_axis_global * force_magnitude) func endInteract(player) -> void: dragging = false