grunk/src/player/hold_component.gd

88 lines
2.4 KiB
GDScript3
Raw Normal View History

extends Node3D
## Component for managing physics object holding
## Held object position lerp acceleration.
@export var hold_accel := 20.0
## 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
## Temporary collision layer.
@export_flags_3d_physics var hold_collision_layer := 0
## Temporary collision mask.
@export_flags_3d_physics var hold_collision_physics := 1
## The object currently being held.
var _held_object: RigidBody3D
var _original_damping: float
var _original_collision_layer: int
var _original_collision_mask: int
var _linear_velocity := Vector3.ZERO
@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)
_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
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.linear_velocity = _linear_velocity
_held_object = null
_linear_velocity = Vector3.ZERO
func holding_object() -> bool:
return !!_held_object
func _physics_process(delta: float) -> void:
# Object hold action logic
if Input.is_action_just_pressed("interact"):
if _held_object:
drop()
elif interact_ray.is_colliding():
var body := interact_ray.get_collider() as RigidBody3D
var hold_component := Holdable.get_component(body)
if hold_component:
attach(body, hold_component.hold_distance)
# Held object logic
if not _held_object:
return
var diff := hold_point.global_position - (_held_object.global_position)
if diff.length() > max_distance:
drop()
return
var held_object_last_position := _held_object.global_position
var weight := 1 - exp(-hold_accel * delta)
_held_object.global_position = _held_object.global_position.lerp(
hold_point.global_position, weight
)
_held_object.global_basis = _held_object.global_basis.slerp(global_basis, weight)
_linear_velocity = (_held_object.global_position - held_object_last_position) / delta