2025-07-04 14:56:35 -06:00
|
|
|
class_name HoldComponent extends Node3D
|
2025-07-03 13:24:54 -06:00
|
|
|
## Component for managing physics object holding
|
|
|
|
|
2025-07-04 15:20:26 -06:00
|
|
|
signal held
|
|
|
|
signal dropped
|
|
|
|
|
2025-07-03 13:24:54 -06:00
|
|
|
## Held object position lerp acceleration.
|
|
|
|
@export var hold_accel := 20.0
|
|
|
|
|
2025-07-03 15:59:59 -06:00
|
|
|
## Held object position velocity scale.
|
|
|
|
@export var hold_speed := 12.0
|
|
|
|
|
2025-07-03 13:24:54 -06:00
|
|
|
## The maximum distance the object may be from the hold point before breaking the hold.
|
|
|
|
@export var max_distance := 3.0
|
|
|
|
|
|
|
|
## Temporary linear damping for held objects
|
|
|
|
@export var hold_damping := 8.0
|
|
|
|
|
2025-07-07 11:18:56 -06:00
|
|
|
## Impulse force when throwing an object
|
|
|
|
@export var throw_force := 100.0
|
|
|
|
|
2025-07-03 13:24:54 -06:00
|
|
|
## Temporary collision layer.
|
2025-07-03 18:05:06 -06:00
|
|
|
@export_flags_3d_physics var hold_collision_layer := 0b01000000
|
2025-07-03 13:24:54 -06:00
|
|
|
|
|
|
|
## Temporary collision mask.
|
2025-07-03 18:05:06 -06:00
|
|
|
@export_flags_3d_physics var hold_collision_physics := 0b01000001
|
2025-07-03 13:24:54 -06:00
|
|
|
|
|
|
|
## The object currently being held.
|
|
|
|
var _held_object: RigidBody3D
|
|
|
|
|
|
|
|
var _original_damping: float
|
|
|
|
var _original_collision_layer: int
|
|
|
|
var _original_collision_mask: int
|
|
|
|
|
|
|
|
@onready var interact_ray: RayCast3D = %InteractRay
|
|
|
|
@onready var hold_point: Marker3D = %HoldPoint
|
|
|
|
|
|
|
|
|
|
|
|
func attach(prop: RigidBody3D, hold_distance: float) -> void:
|
|
|
|
hold_point.position = Vector3(0, 0, -hold_distance)
|
2025-07-07 11:18:56 -06:00
|
|
|
hold_point.global_basis = global_basis
|
2025-07-03 13:24:54 -06:00
|
|
|
_held_object = prop
|
|
|
|
|
|
|
|
_original_damping = prop.linear_damp
|
|
|
|
prop.linear_damp = hold_damping
|
|
|
|
|
|
|
|
_original_collision_layer = prop.collision_layer
|
|
|
|
prop.collision_layer = hold_collision_layer
|
|
|
|
|
|
|
|
_original_collision_mask = prop.collision_mask
|
|
|
|
prop.collision_mask = hold_collision_physics
|
|
|
|
|
2025-07-04 15:20:26 -06:00
|
|
|
held.emit()
|
2025-07-04 14:56:35 -06:00
|
|
|
|
2025-07-03 13:24:54 -06:00
|
|
|
|
|
|
|
func drop() -> void:
|
|
|
|
_held_object.linear_damp = _original_damping
|
|
|
|
_held_object.collision_layer = _original_collision_layer
|
|
|
|
_held_object.collision_mask = _original_collision_mask
|
|
|
|
_held_object = null
|
|
|
|
|
2025-07-04 15:20:26 -06:00
|
|
|
dropped.emit()
|
2025-07-04 14:56:35 -06:00
|
|
|
|
2025-07-03 13:24:54 -06:00
|
|
|
|
2025-07-07 11:18:56 -06:00
|
|
|
func throw() -> void:
|
|
|
|
var impulse := -global_basis.z.normalized() * throw_force
|
|
|
|
_held_object.apply_central_impulse(impulse)
|
|
|
|
drop()
|
|
|
|
|
|
|
|
|
2025-07-03 13:24:54 -06:00
|
|
|
func holding_object() -> bool:
|
|
|
|
return !!_held_object
|
|
|
|
|
|
|
|
|
2025-07-07 11:18:56 -06:00
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
|
|
if event is InputEventMouseMotion:
|
|
|
|
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED and holding_object():
|
|
|
|
print(event)
|
|
|
|
|
|
|
|
|
|
|
|
func _process_hold_controls() -> void:
|
|
|
|
if Input.is_action_just_pressed("interact"):
|
|
|
|
drop()
|
|
|
|
elif Input.is_action_just_pressed("fire"):
|
|
|
|
throw()
|
|
|
|
|
|
|
|
|
2025-07-03 13:24:54 -06:00
|
|
|
func _physics_process(delta: float) -> void:
|
|
|
|
# Object hold action logic
|
2025-07-07 11:18:56 -06:00
|
|
|
if holding_object():
|
|
|
|
_process_hold_controls()
|
2025-07-03 13:24:54 -06:00
|
|
|
|
|
|
|
# Held object logic
|
2025-07-04 14:56:35 -06:00
|
|
|
if not holding_object():
|
2025-07-03 13:24:54 -06:00
|
|
|
return
|
|
|
|
|
|
|
|
var diff := hold_point.global_position - (_held_object.global_position)
|
|
|
|
if diff.length() > max_distance:
|
|
|
|
drop()
|
|
|
|
return
|
|
|
|
|
|
|
|
var weight := 1 - exp(-hold_accel * delta)
|
2025-07-03 15:59:59 -06:00
|
|
|
_held_object.linear_velocity = _held_object.linear_velocity.lerp(diff * hold_speed, weight)
|
2025-07-07 11:18:56 -06:00
|
|
|
_held_object.global_basis = _held_object.global_basis.slerp(hold_point.global_basis, weight)
|