xrjamfeb2025/assets/digitaln8m4r3/scripts/firearm_slide.gd

113 lines
3.2 KiB
GDScript

@tool
class_name XRFirearmSlide
extends XRToolsInteractableHandleDriven
## XR Firearm Slide script
##
## The firearm slide is a slider transform node controlled by the
## player through [XRToolsInteractableHandle] instances.
##
## The slider translates itelf along its local Z axis, and so should be
## placed as a child of a node to translate and rotate as appropriate.
##
## The interactable slider is not a [RigidBody3D], and as such will not react
## to any collisions.
## Signal for slider moved
signal firearm_slider_moved(position)
## Start position for slide, can be positiv and negativ in values
@export var slider_start : float = 0.0
## End position for slide, can be positiv and negativ in values
@export var slider_end : float = 1.0
## Slider position - move to test the position setup
@export var slider_position : float = 0.0: set = _set_slider_position
## Default position
@export var default_position : float = 0.0
## If true, the slider moves to the default position when released
@export var default_on_release : bool = false
# Add support for is_xr_class on XRTools classes
func is_xr_class(name : String) -> bool:
return name == "XRFirearmSlide" or super(name)
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
# In Godot 4 we must now manually call our super class ready function
super()
# Set the initial position to match the initial slider position value
transform = Transform3D(
Basis.IDENTITY,
Vector3(0.0, 0.0, slider_position)
)
# Connect signals
if released.connect(_on_slider_released):
push_error("Cannot connect slider released signal")
# Called every frame when one or more handles are held by the player
func _process(_delta: float) -> void:
# Get the total handle offsets
var offset_sum := Vector3.ZERO
for item in grabbed_handles:
var handle := item as XRToolsInteractableHandle
offset_sum += handle.global_transform.origin - handle.handle_origin.global_transform.origin
# Rotate the offset sum vector from global into local coordinate space
offset_sum = offset_sum * global_transform.basis
# Get the average displacement in the Z axis
var offset := offset_sum.z / grabbed_handles.size()
# Move the slider by the requested offset
move_slider(slider_position + offset)
# Move the slider to the specified position
func move_slider(new_position: float) -> void:
# Do the slider move
new_position = _do_move_slider(new_position)
if new_position == slider_position:
return
# Update the current position
slider_position = new_position
# Emit the moved signal
emit_signal("firearm_slider_moved", new_position)
# Handle release of slider
func _on_slider_released(_interactable: XRFirearmSlide):
if default_on_release:
move_slider(default_position)
# Called when the slider position is set externally
func _set_slider_position(new_position: float) -> void:
new_position = _do_move_slider(new_position)
slider_position = new_position
# Do the slider move
func _do_move_slider(new_position: float) -> float:
# Apply slider limits
new_position = clamp(new_position, slider_start, slider_end)
# Move if necessary
if new_position != slider_position:
transform.origin.z = new_position
# Return the updated position
return new_position