extends RigidBody3D class_name Dart var dragging: bool = false var drag_plane: Plane var drag_offset: Vector3 = Vector3.ZERO var target_pos: Vector3 = Vector3.ZERO # velocity tracking for release throw var position_history: Array[Vector3] = [] var time_history: Array[float] = [] const HISTORY_LENGTH = 5 # drag "stiffness" tuning @export var drag_follow_speed: float = 20.0 # how fast it chases the mouse @export var max_drag_speed: float = 15.0 # clamp so it doesn't go insane @export_range(-180,180) var angle_of_plane: float = 15.0 func start_drag(camera: Camera3D, mouse_pos: Vector2, hit_point: Vector3): dragging = true # keep it physics-active — don't freeze gravity_scale = 0.0 # optional: ignore gravity while held so it doesn't sag linear_damp = 4.0 # optional: a bit of damping for stability while dragged #drag_plane = Plane(camera.global_transform.basis.z, hit_point) var base_normal = camera.global_transform.basis.z var tilt = base_normal.rotated(camera.global_transform.basis.x, deg_to_rad(angle_of_plane)) # tilt adjustable around camera's right axis drag_plane = Plane(tilt.normalized(), hit_point) drag_offset = global_position - hit_point position_history.clear() time_history.clear() func update_drag(camera: Camera3D, mouse_pos: Vector2): if not dragging: return var ray_origin = camera.project_ray_origin(mouse_pos) var ray_dir = camera.project_ray_normal(mouse_pos) var intersection = drag_plane.intersects_ray(ray_origin, ray_dir) if intersection: target_pos = intersection + drag_offset func _physics_process(delta): if dragging: # chase the target position with velocity instead of teleporting var to_target = target_pos - global_position var desired_velocity = to_target * drag_follow_speed if desired_velocity.length() > max_drag_speed: desired_velocity = desired_velocity.normalized() * max_drag_speed linear_velocity = desired_velocity angular_velocity = angular_velocity.lerp(Vector3.ZERO, 0.2) # optional: damp spin while dragging # track actual position for momentum calc on release position_history.append(global_position) time_history.append(Time.get_ticks_msec() / 1000.0) if position_history.size() > HISTORY_LENGTH: position_history.pop_front() time_history.pop_front() func release_drag(): if not dragging: return dragging = false gravity_scale = 2 linear_damp = 1.0 # reset to whatever your normal dart damping is var velocity = calculate_throw_velocity() * 1.0 linear_velocity = velocity # angular_velocity left as-is from physics, or compute your own spin here func calculate_throw_velocity() -> Vector3: if position_history.size() < 2: return linear_velocity # fallback to whatever physics already had var start_pos = position_history[0] var end_pos = position_history[position_history.size() - 1] var start_time = time_history[0] var end_time = time_history[time_history.size() - 1] var dt = end_time - start_time if dt <= 0.0: return linear_velocity return (end_pos - start_pos) / dt