82 lines
2.2 KiB
GDScript3
82 lines
2.2 KiB
GDScript3
|
@tool
|
||
|
class_name XRToolsInteractableHandleDriven
|
||
|
extends Node3D
|
||
|
|
||
|
|
||
|
## XR Tools Interactable Handle Driven script
|
||
|
##
|
||
|
## This is the base class for interactables driven by handles. It subscribes
|
||
|
## to all child handle picked_up and dropped signals, and maintains a list
|
||
|
## of all grabbed handles.
|
||
|
##
|
||
|
## When one or more handles are grabbed, the _process function is enabled
|
||
|
## to process the handle-driven movement.
|
||
|
|
||
|
|
||
|
## Signal called when this interactable is grabbed
|
||
|
signal grabbed(interactable)
|
||
|
|
||
|
## Signal called when this interactable is released
|
||
|
signal released(interactable)
|
||
|
|
||
|
|
||
|
# Array of handles currently grabbed
|
||
|
var grabbed_handles := Array()
|
||
|
|
||
|
|
||
|
# Add support for is_xr_class on XRTools classes
|
||
|
func is_xr_class(name : String) -> bool:
|
||
|
return name == "XRToolsInteractableHandleDriven"
|
||
|
|
||
|
|
||
|
# Called when the node enters the scene tree for the first time.
|
||
|
func _ready():
|
||
|
# Hook picked_up and dropped signals from all child handles
|
||
|
_hook_child_handles(self)
|
||
|
|
||
|
# Turn off processing until a handle is grabbed
|
||
|
set_process(false)
|
||
|
|
||
|
|
||
|
# Called when a handle is picked up
|
||
|
func _on_handle_picked_up(handle: XRToolsInteractableHandle) -> void:
|
||
|
# Append to the list of grabbed handles
|
||
|
grabbed_handles.append(handle)
|
||
|
|
||
|
# Enable processing
|
||
|
if grabbed_handles.size() == 1:
|
||
|
# Report grabbed
|
||
|
emit_signal("grabbed", self)
|
||
|
|
||
|
# Enable physics processing
|
||
|
set_process(true)
|
||
|
|
||
|
|
||
|
# Called when a handle is dropped
|
||
|
func _on_handle_dropped(handle: XRToolsInteractableHandle) -> void:
|
||
|
# Remove from the list of grabbed handles
|
||
|
grabbed_handles.erase(handle)
|
||
|
|
||
|
# Disable processing when we drop the last handle
|
||
|
if grabbed_handles.is_empty():
|
||
|
# Disable physics processing
|
||
|
set_process(false)
|
||
|
|
||
|
# Report released
|
||
|
emit_signal("released", self)
|
||
|
|
||
|
|
||
|
# Recursive function to hook picked_up and dropped signals in all child handles
|
||
|
func _hook_child_handles(node: Node) -> void:
|
||
|
# If this node is a handle then hook its handle signals
|
||
|
var handle := node as XRToolsInteractableHandle
|
||
|
if handle:
|
||
|
if handle.picked_up.connect(_on_handle_picked_up):
|
||
|
push_error("Unable to connect handle signal")
|
||
|
if handle.dropped.connect(_on_handle_dropped):
|
||
|
push_error("Unable to connect handle signal")
|
||
|
|
||
|
# Recurse into all children
|
||
|
for child in node.get_children():
|
||
|
_hook_child_handles(child)
|