extends RigidBody3D class_name Grabbable_Object @export var grabbable: bool = true var is_grabbed: bool = false var original_parent: Node = null @export var grab_offset: Vector3 = Vector3(0.0, 0.0, -1.0) @export var drop_forward_offset: float = 1.0 @export var weight: float = 5.0 @export var max_linear_speed: float = 15.0 @export var max_angular_speed: float = 10.0 func _integrate_forces(state: PhysicsDirectBodyState3D) -> void: # Limit linear speed if state.linear_velocity.length() > max_linear_speed: state.linear_velocity = state.linear_velocity.normalized() * max_linear_speed # Limit speed of rotation (optional) if state.angular_velocity.length() > max_angular_speed: state.angular_velocity = state.angular_velocity.normalized() * max_angular_speed func grab(player: Node3D): if not grabbable or is_grabbed or player.grabbed_item: return is_grabbed = true original_parent = get_parent() # Disable physics gravity_scale = 0.0 linear_velocity = Vector3.ZERO angular_velocity = Vector3.ZERO freeze = true $CollisionShape3D.disabled = true # Reparent under player var current_transform = global_transform get_parent().remove_child(self) player.add_child(self) player.grabbed_item = self print(player.grabbed_item) global_transform = current_transform # Move above player's head position = grab_offset rotation = Vector3(0,0,0) func can_drop(player: Node3D) -> bool: var space_state = get_world_3d().direct_space_state var start = player.global_position + Vector3(0, 2, 0) var forward_dir = -player.global_transform.basis.z.normalized() var end = start + forward_dir * drop_forward_offset var query = PhysicsRayQueryParameters3D.create(start, end) query.exclude = [player] var result = space_state.intersect_ray(query) return result.is_empty() func release(player: Node3D, throw := false): if not is_grabbed or not can_drop(player): return is_grabbed = false # Re-enable physics $CollisionShape3D.disabled = false freeze = false gravity_scale = 1.0 # Reparent back to world var current_transform = global_transform get_parent().remove_child(self) original_parent.add_child(self) global_transform = current_transform # Place in front of player var forward_dir = -player.global_transform.basis.z.normalized() var player_velocity = player.velocity if player is CharacterBody3D else Vector3.ZERO var throw_dir = Vector3(0,2.0,0) + forward_dir + (player_velocity * 0.25) global_position = player.global_position + Vector3(0, 1.5, 0) + forward_dir * drop_forward_offset # Give it a small push forward (optional) if throw: apply_impulse(throw_dir * 0.01) else: apply_impulse(forward_dir * 0.001) player.grabbed_item = null func get_weight(): return weight