add vr template project
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
class_name Grab
|
||||
extends Grabber
|
||||
|
||||
|
||||
## Grab Class
|
||||
##
|
||||
## This class encodes information about an active grab. Additionally it applies
|
||||
## hand poses and collision exceptions as appropriate.
|
||||
|
||||
|
||||
## Priority for grip poses
|
||||
const GRIP_POSE_PRIORITY := 100
|
||||
|
||||
## Priority for grip targeting
|
||||
const GRIP_TARGET_PRIORITY := 100
|
||||
|
||||
|
||||
## Grab target
|
||||
var what : XRToolsPickable
|
||||
|
||||
## Grab point information
|
||||
var point : XRToolsGrabPoint
|
||||
|
||||
## Hand grab point information
|
||||
var hand_point : XRToolsGrabPointHand
|
||||
|
||||
## Grab transform
|
||||
var transform : Transform3D
|
||||
|
||||
## Position drive strength
|
||||
var drive_position : float = 1.0
|
||||
|
||||
## Angle drive strength
|
||||
var drive_angle : float = 1.0
|
||||
|
||||
## Aim drive strength
|
||||
var drive_aim : float = 0.0
|
||||
|
||||
## Has target arrived at grab point
|
||||
var _arrived : bool = false
|
||||
|
||||
|
||||
## Initialize the grab
|
||||
func _init(
|
||||
p_grabber : Grabber,
|
||||
p_what : XRToolsPickable,
|
||||
p_point : XRToolsGrabPoint,
|
||||
p_precise : bool) -> void:
|
||||
|
||||
# Copy the grabber information
|
||||
by = p_grabber.by
|
||||
pickup = p_grabber.pickup
|
||||
controller = p_grabber.controller
|
||||
hand = p_grabber.hand
|
||||
collision_hand = p_grabber.collision_hand
|
||||
|
||||
# Set the point
|
||||
what = p_what
|
||||
point = p_point
|
||||
hand_point = p_point as XRToolsGrabPointHand
|
||||
|
||||
# Calculate the grab transform
|
||||
if p_point:
|
||||
transform = p_point.transform
|
||||
elif p_precise:
|
||||
transform = p_what.global_transform.inverse() * by.global_transform
|
||||
else:
|
||||
transform = Transform3D.IDENTITY
|
||||
|
||||
# Set the drive parameters
|
||||
if hand_point:
|
||||
drive_position = hand_point.drive_position
|
||||
drive_angle = hand_point.drive_angle
|
||||
drive_aim = hand_point.drive_aim
|
||||
|
||||
# Apply collision exceptions
|
||||
if collision_hand:
|
||||
what.add_collision_exception_with(collision_hand)
|
||||
collision_hand.add_collision_exception_with(what)
|
||||
|
||||
|
||||
## Set the target as arrived at the grab-point
|
||||
func set_arrived() -> void:
|
||||
# Ignore if already arrived
|
||||
if _arrived:
|
||||
return
|
||||
|
||||
# Set arrived and apply any hand pose
|
||||
print_verbose("%s> arrived at %s" % [what.name, point])
|
||||
_arrived = true
|
||||
_set_hand_pose()
|
||||
|
||||
# Report the grab
|
||||
print_verbose("%s> grabbed by %s", [what.name, by.name])
|
||||
what.grabbed.emit(what, by)
|
||||
|
||||
|
||||
## Set the grab point
|
||||
func set_grab_point(p_point : XRToolsGrabPoint) -> void:
|
||||
# Skip if no change
|
||||
if p_point == point:
|
||||
return
|
||||
|
||||
# Remove any current pose override
|
||||
_clear_hand_pose()
|
||||
|
||||
# Update the grab point
|
||||
point = p_point
|
||||
hand_point = point as XRToolsGrabPointHand
|
||||
|
||||
# Update the transform
|
||||
if point:
|
||||
transform = point.transform
|
||||
|
||||
# Apply the new hand grab-point settings
|
||||
if hand_point:
|
||||
drive_position = hand_point.drive_position
|
||||
drive_angle = hand_point.drive_angle
|
||||
drive_aim = hand_point.drive_aim
|
||||
|
||||
# Apply any pose overrides
|
||||
if _arrived:
|
||||
_set_hand_pose()
|
||||
|
||||
# Report switch
|
||||
print_verbose("%s> switched grab point to %s", [what.name, point.name])
|
||||
what.released.emit(what, by)
|
||||
what.grabbed.emit(what, by)
|
||||
|
||||
|
||||
## Release the grip
|
||||
func release() -> void:
|
||||
# Clear any hand pose
|
||||
_clear_hand_pose()
|
||||
|
||||
# Remove collision exceptions
|
||||
if is_instance_valid(collision_hand):
|
||||
what.remove_collision_exception_with(collision_hand)
|
||||
collision_hand.remove_collision_exception_with(what)
|
||||
|
||||
# Report the release
|
||||
print_verbose("%s> released by %s", [what.name, by.name])
|
||||
what.released.emit(what, by)
|
||||
|
||||
|
||||
# Set hand-pose overrides
|
||||
func _set_hand_pose() -> void:
|
||||
# Skip if not hand
|
||||
if not is_instance_valid(hand) or not is_instance_valid(hand_point):
|
||||
return
|
||||
|
||||
# Apply the hand-pose
|
||||
if hand_point.hand_pose:
|
||||
hand.add_pose_override(hand_point, GRIP_POSE_PRIORITY, hand_point.hand_pose)
|
||||
|
||||
# Apply hand snapping
|
||||
if hand_point.snap_hand:
|
||||
hand.add_target_override(hand_point, GRIP_TARGET_PRIORITY)
|
||||
|
||||
|
||||
# Clear any hand-pose overrides
|
||||
func _clear_hand_pose() -> void:
|
||||
# Skip if not hand
|
||||
if not is_instance_valid(hand) or not is_instance_valid(hand_point):
|
||||
return
|
||||
|
||||
# Remove hand-pose
|
||||
hand.remove_pose_override(hand_point)
|
||||
|
||||
# Remove hand snapping
|
||||
hand.remove_target_override(hand_point)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dldogfjp88w5w
|
||||
@@ -0,0 +1,216 @@
|
||||
class_name XRToolsGrabDriver
|
||||
extends RemoteTransform3D
|
||||
|
||||
|
||||
## Grab state
|
||||
enum State {
|
||||
LERP,
|
||||
SNAP,
|
||||
}
|
||||
|
||||
|
||||
## Drive state
|
||||
var state : State = State.SNAP
|
||||
|
||||
## Target pickable
|
||||
var target : XRToolsPickable
|
||||
|
||||
## Primary grab information
|
||||
var primary : Grab = null
|
||||
|
||||
## Secondary grab information
|
||||
var secondary : Grab = null
|
||||
|
||||
## Lerp start position
|
||||
var lerp_start : Transform3D
|
||||
|
||||
## Lerp total duration
|
||||
var lerp_duration : float = 1.0
|
||||
|
||||
## Lerp time
|
||||
var lerp_time : float = 0.0
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _physics_process(delta : float) -> void:
|
||||
# Skip if no primary node
|
||||
if not is_instance_valid(primary):
|
||||
return
|
||||
|
||||
# Set destination from primary grab
|
||||
var destination := primary.by.global_transform * primary.transform.inverse()
|
||||
|
||||
# If present, apply secondary-node contributions
|
||||
if is_instance_valid(secondary):
|
||||
# Calculate lerp coefficients based on drive strengths
|
||||
var position_lerp := _vote(primary.drive_position, secondary.drive_position)
|
||||
var angle_lerp := _vote(primary.drive_angle, secondary.drive_angle)
|
||||
|
||||
# Calculate the transform from secondary grab
|
||||
var x1 := destination
|
||||
var x2 := secondary.by.global_transform * secondary.transform.inverse()
|
||||
|
||||
# Independently lerp the angle and position
|
||||
destination = Transform3D(
|
||||
x1.basis.slerp(x2.basis, angle_lerp),
|
||||
x1.origin.lerp(x2.origin, position_lerp))
|
||||
|
||||
# Test if we need to apply aiming
|
||||
if secondary.drive_aim > 0.0:
|
||||
# Convert destination from global to primary-local
|
||||
destination = primary.by.global_transform.inverse() * destination
|
||||
|
||||
# Calculate the from and to vectors in primary-local space
|
||||
var secondary_from := destination * secondary.transform.origin
|
||||
var secondary_to := primary.by.to_local(secondary.by.global_position)
|
||||
|
||||
# Build shortest arc
|
||||
secondary_from = secondary_from.normalized()
|
||||
secondary_to = secondary_to.normalized()
|
||||
var spherical := Quaternion(secondary_from, secondary_to)
|
||||
|
||||
# Build aim-rotation
|
||||
var rotate := Basis.IDENTITY.slerp(Basis(spherical), secondary.drive_aim)
|
||||
destination = Transform3D(rotate, Vector3.ZERO) * destination
|
||||
|
||||
# Convert destination from primary-local to global
|
||||
destination = primary.by.global_transform * destination
|
||||
|
||||
# Handle update
|
||||
match state:
|
||||
State.LERP:
|
||||
# Progress the lerp
|
||||
lerp_time += delta
|
||||
if lerp_time < lerp_duration:
|
||||
# Interpolate from lerp_start to destination
|
||||
destination = lerp_start.interpolate_with(
|
||||
destination,
|
||||
lerp_time / lerp_duration)
|
||||
else:
|
||||
# Lerp completed
|
||||
state = State.SNAP
|
||||
if primary: primary.set_arrived()
|
||||
if secondary: secondary.set_arrived()
|
||||
|
||||
# Apply the destination transform
|
||||
global_transform = destination
|
||||
force_update_transform()
|
||||
if is_instance_valid(target):
|
||||
target.force_update_transform()
|
||||
|
||||
|
||||
## Set the secondary grab point
|
||||
func add_grab(p_grab : Grab) -> void:
|
||||
# Set the secondary grab
|
||||
if p_grab.hand_point and p_grab.hand_point.mode == XRToolsGrabPointHand.Mode.PRIMARY:
|
||||
print_verbose("%s> new primary grab %s" % [target.name, p_grab.by.name])
|
||||
secondary = primary
|
||||
primary = p_grab
|
||||
else:
|
||||
print_verbose("%s> new secondary grab %s" % [target.name, p_grab.by.name])
|
||||
secondary = p_grab
|
||||
|
||||
# If snapped then report arrived at the new grab
|
||||
if state == State.SNAP:
|
||||
p_grab.set_arrived()
|
||||
|
||||
|
||||
## Get the grab information for the grab node
|
||||
func get_grab(by : Node3D) -> Grab:
|
||||
if primary and primary.by == by:
|
||||
return primary
|
||||
|
||||
if secondary and secondary.by == by:
|
||||
return secondary
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func remove_grab(p_grab : Grab) -> void:
|
||||
# Remove the appropriate grab
|
||||
if p_grab == primary:
|
||||
# Remove primary (secondary promoted)
|
||||
print_verbose("%s> %s (primary) released" % [target.name, p_grab.by.name])
|
||||
primary = secondary
|
||||
secondary = null
|
||||
elif p_grab == secondary:
|
||||
# Remove secondary
|
||||
print_verbose("%s> %s (secondary) released" % [target.name, p_grab.by.name])
|
||||
secondary = null
|
||||
|
||||
|
||||
# Discard the driver
|
||||
func discard():
|
||||
remote_path = NodePath()
|
||||
queue_free()
|
||||
|
||||
|
||||
# Create the driver to lerp the target from its current location to the
|
||||
# primary grab-point.
|
||||
static func create_lerp(
|
||||
p_target : Node3D,
|
||||
p_grab : Grab,
|
||||
p_lerp_speed : float) -> XRToolsGrabDriver:
|
||||
|
||||
print_verbose("%s> lerping %s" % [p_target.name, p_grab.by.name])
|
||||
|
||||
# Construct the driver lerping from the current position
|
||||
var driver := XRToolsGrabDriver.new()
|
||||
driver.name = p_target.name + "_driver"
|
||||
driver.top_level = true
|
||||
driver.process_physics_priority = -80
|
||||
driver.state = State.LERP
|
||||
driver.target = p_target
|
||||
driver.primary = p_grab
|
||||
driver.global_transform = p_target.global_transform
|
||||
|
||||
# Calculate the start and duration
|
||||
var end := p_grab.by.global_transform * p_grab.transform
|
||||
var delta := end.origin - p_target.global_position
|
||||
driver.lerp_start = p_target.global_transform
|
||||
driver.lerp_duration = delta.length() / p_lerp_speed
|
||||
|
||||
# Add the driver as a neighbor of the target as RemoteTransform3D nodes
|
||||
# cannot be descendands of the targets they drive.
|
||||
p_target.get_parent().add_child(driver)
|
||||
driver.remote_path = driver.get_path_to(p_target)
|
||||
|
||||
# Return the driver
|
||||
return driver
|
||||
|
||||
|
||||
# Create the driver to instantly snap to the primary grab-point.
|
||||
static func create_snap(
|
||||
p_target : Node3D,
|
||||
p_grab : Grab) -> XRToolsGrabDriver:
|
||||
|
||||
print_verbose("%s> snapping to %s" % [p_target.name, p_grab.by.name])
|
||||
|
||||
# Construct the driver snapped to the held position
|
||||
var driver := XRToolsGrabDriver.new()
|
||||
driver.name = p_target.name + "_driver"
|
||||
driver.top_level = true
|
||||
driver.process_physics_priority = -80
|
||||
driver.state = State.SNAP
|
||||
driver.target = p_target
|
||||
driver.primary = p_grab
|
||||
driver.global_transform = p_grab.by.global_transform * p_grab.transform.inverse()
|
||||
|
||||
# Snapped to grab-point so report arrived
|
||||
p_grab.set_arrived()
|
||||
|
||||
# Add the driver as a neighbor of the target as RemoteTransform3D nodes
|
||||
# cannot be descendands of the targets they drive.
|
||||
p_target.get_parent().add_child(driver)
|
||||
driver.remote_path = driver.get_path_to(p_target)
|
||||
|
||||
# Return the driver
|
||||
return driver
|
||||
|
||||
|
||||
# Calculate the lerp voting from a to b
|
||||
static func _vote(a : float, b : float) -> float:
|
||||
if a == 0.0 and b == 0.0:
|
||||
return 0.0
|
||||
|
||||
return b / (a + b)
|
||||
@@ -0,0 +1 @@
|
||||
uid://40m5rmpwo51
|
||||
@@ -0,0 +1,28 @@
|
||||
class_name XRToolsGrabPoint
|
||||
extends Marker3D
|
||||
|
||||
|
||||
## XR Tools Grab Point Base Script
|
||||
##
|
||||
## This script is the base for all grab points. Pickable object extending from
|
||||
## [XRToolsPickable] can have numerous grab points to control where the object
|
||||
## is grabbed from.
|
||||
|
||||
|
||||
## If true, the grab point is enabled for grabbing
|
||||
@export var enabled : bool = true
|
||||
|
||||
|
||||
## Evaluate fitness of the proposed grab, with 0.0 for not allowed.
|
||||
func can_grab(grabber : Node3D, _current : XRToolsGrabPoint) -> float:
|
||||
if not enabled:
|
||||
return 0.0
|
||||
|
||||
# Return the distance-weighted fitness
|
||||
return _weight(grabber)
|
||||
|
||||
|
||||
# Return a distance-weighted fitness weight in the range (0.0 - max]
|
||||
func _weight(grabber : Node3D, max : float = 1.0) -> float:
|
||||
var distance := global_position.distance_to(grabber.global_position)
|
||||
return max / (1.0 + distance)
|
||||
@@ -0,0 +1 @@
|
||||
uid://d3qll1uorg88f
|
||||
@@ -0,0 +1,213 @@
|
||||
@tool
|
||||
class_name XRToolsGrabPointHand
|
||||
extends XRToolsGrabPoint
|
||||
|
||||
|
||||
## XR Tools Grab Point Hand Script
|
||||
##
|
||||
## This script allows specifying a grab point for a specific hand. Additionally
|
||||
## the grab point can be used to control the pose of the hand, and to allow the
|
||||
## grab point position to be fine-tuned in the editor.
|
||||
|
||||
|
||||
## Hand for this grab point
|
||||
enum Hand {
|
||||
LEFT, ## Left hand
|
||||
RIGHT, ## Right hand
|
||||
}
|
||||
|
||||
## Grab mode for this grab point
|
||||
enum Mode {
|
||||
GENERAL, ## General grab point
|
||||
PRIMARY, ## Primary-hand grab point
|
||||
SECONDARY ## Secondary-hand grab point
|
||||
}
|
||||
|
||||
## Hand preview option
|
||||
enum PreviewMode {
|
||||
CLOSED, ## Preview hand closed
|
||||
OPEN, ## Preview hand open
|
||||
}
|
||||
|
||||
|
||||
## Left hand scene path (for editor preview)
|
||||
const LEFT_HAND_PATH := "res://addons/godot-xr-tools/hands/scenes/lowpoly/left_hand_low.tscn"
|
||||
|
||||
## Right hand scene path (for editor preview)
|
||||
const RIGHT_HAND_PATH := "res://addons/godot-xr-tools/hands/scenes/lowpoly/right_hand_low.tscn"
|
||||
|
||||
|
||||
## Grab-point handle
|
||||
@export var handle : String
|
||||
|
||||
## Which hand this grab point is for
|
||||
@export var hand : Hand: set = _set_hand
|
||||
|
||||
## Hand grab mode
|
||||
@export var mode : Mode = Mode.GENERAL
|
||||
|
||||
## Snap the hand mesh to the grab-point
|
||||
@export var snap_hand : bool = true
|
||||
|
||||
## Hand pose
|
||||
@export var hand_pose : XRToolsHandPoseSettings: set = _set_hand_pose
|
||||
|
||||
## If true, the hand is shown in the editor
|
||||
@export var editor_preview_mode : PreviewMode = PreviewMode.CLOSED: set = _set_editor_preview_mode
|
||||
|
||||
## How much this grab-point drives the position
|
||||
@export var drive_position : float = 1.0
|
||||
|
||||
## How much this grab-point drives the angle
|
||||
@export var drive_angle : float = 1.0
|
||||
|
||||
## How much this grab-point drives the aim
|
||||
@export var drive_aim : float = 0.0
|
||||
|
||||
|
||||
## Hand to use for editor preview
|
||||
var _editor_preview_hand : XRToolsHand
|
||||
|
||||
|
||||
## Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
# If in the editor then update the preview
|
||||
if Engine.is_editor_hint():
|
||||
_update_editor_preview()
|
||||
|
||||
|
||||
## Test if a grabber can grab by this grab-point
|
||||
func can_grab(grabber : Node3D, current : XRToolsGrabPoint) -> float:
|
||||
# Skip if not enabled
|
||||
if not enabled:
|
||||
return 0.0
|
||||
|
||||
# Verify the hand matches
|
||||
if not _is_correct_hand(grabber):
|
||||
return 0.0
|
||||
|
||||
# Fail if the hand grab is not permitted
|
||||
if not _is_valid_hand_grab(current):
|
||||
return 0.0
|
||||
|
||||
# Get the distance-weighted fitness in the range (0.0 - 0.5], but boost
|
||||
# to [0.5 - 1.0] for valid "specific" grabs.
|
||||
var fitness := _weight(grabber, 0.5)
|
||||
if mode != Mode.GENERAL:
|
||||
fitness += 0.5
|
||||
|
||||
# Return the grab fitness
|
||||
return fitness
|
||||
|
||||
|
||||
func _set_hand(new_value : Hand) -> void:
|
||||
hand = new_value
|
||||
if Engine.is_editor_hint():
|
||||
_update_editor_preview()
|
||||
|
||||
|
||||
func _set_hand_pose(new_value : XRToolsHandPoseSettings) -> void:
|
||||
# Unsubscribe from the old hand-pose changed signal
|
||||
if Engine.is_editor_hint() and hand_pose:
|
||||
hand_pose.changed.disconnect(_update_editor_preview)
|
||||
|
||||
# Save the hand pose
|
||||
hand_pose = new_value
|
||||
|
||||
# Update the editor preview
|
||||
if Engine.is_editor_hint() and hand_pose:
|
||||
hand_pose.changed.connect(_update_editor_preview)
|
||||
_update_editor_preview()
|
||||
|
||||
|
||||
func _set_editor_preview_mode(new_value : PreviewMode) -> void:
|
||||
editor_preview_mode = new_value
|
||||
if Engine.is_editor_hint():
|
||||
_update_editor_preview()
|
||||
|
||||
|
||||
func _update_editor_preview() -> void:
|
||||
# Discard any existing hand model
|
||||
if _editor_preview_hand:
|
||||
remove_child(_editor_preview_hand)
|
||||
_editor_preview_hand.queue_free()
|
||||
_editor_preview_hand = null
|
||||
|
||||
# Pick the hand scene
|
||||
var hand_path := LEFT_HAND_PATH if hand == Hand.LEFT else RIGHT_HAND_PATH
|
||||
var hand_scene : PackedScene = load(hand_path)
|
||||
if !hand_scene:
|
||||
return
|
||||
|
||||
# Construct the model
|
||||
_editor_preview_hand = hand_scene.instantiate()
|
||||
|
||||
# Set the pose
|
||||
if hand_pose:
|
||||
_editor_preview_hand.add_pose_override(self, 0.0, hand_pose)
|
||||
|
||||
# Set the grip override
|
||||
if editor_preview_mode == PreviewMode.CLOSED:
|
||||
_editor_preview_hand.force_grip_trigger(1.0, 1.0)
|
||||
else:
|
||||
_editor_preview_hand.force_grip_trigger(0.0, 0.0)
|
||||
|
||||
# Add the editor-preview hand as a child
|
||||
add_child(_editor_preview_hand)
|
||||
|
||||
|
||||
# Is the grabber for the correct hand
|
||||
func _is_correct_hand(grabber : Node3D) -> bool:
|
||||
# Find the controller
|
||||
var controller := _get_grabber_controller(grabber)
|
||||
if not controller:
|
||||
return false
|
||||
|
||||
# If left hand then verify left controller
|
||||
if hand == Hand.LEFT and controller.tracker != "left_hand":
|
||||
return false
|
||||
|
||||
# If right hand then verify right controller
|
||||
if hand == Hand.RIGHT and controller.tracker != "right_hand":
|
||||
return false
|
||||
|
||||
# Controller matches hand
|
||||
return true
|
||||
|
||||
|
||||
# Test if hand grab is permitted
|
||||
func _is_valid_hand_grab(current : XRToolsGrabPoint) -> bool:
|
||||
# Not a valid hand grab if currently held by something other than a hand
|
||||
var current_hand := current as XRToolsGrabPointHand
|
||||
if current and not current_hand:
|
||||
return false
|
||||
|
||||
# Not valid if grabbing the same named handle
|
||||
if handle and current_hand and handle == current_hand.handle:
|
||||
return false
|
||||
|
||||
# Not valid if attempting PRIMARY grab while current is PRIMARY
|
||||
if mode == Mode.PRIMARY and current_hand and current_hand.mode == Mode.PRIMARY:
|
||||
return false
|
||||
|
||||
# Not valid if attempting SECONDARY grab while no current
|
||||
if mode == Mode.SECONDARY and not current_hand:
|
||||
return false
|
||||
|
||||
# Hand is allowed to grab
|
||||
return true
|
||||
|
||||
|
||||
# Get the controller associated with a grabber
|
||||
static func _get_grabber_controller(grabber : Node3D) -> XRController3D:
|
||||
# Ensure the grabber is valid
|
||||
if not is_instance_valid(grabber):
|
||||
return null
|
||||
|
||||
# Ensure the pickup is a function pickup for a controller
|
||||
var pickup := grabber as XRToolsFunctionPickup
|
||||
if not pickup:
|
||||
return null
|
||||
|
||||
# Get the controller associated with the pickup
|
||||
return pickup.get_controller()
|
||||
@@ -0,0 +1 @@
|
||||
uid://obchv1tx4crh
|
||||
@@ -0,0 +1,7 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://c25yxb0vt53vc"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand.gd" id="1"]
|
||||
|
||||
[node name="GrabPointHandLeft" type="Marker3D"]
|
||||
visible = false
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,8 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://ctw7nbntd5pcj"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand.gd" id="1"]
|
||||
|
||||
[node name="GrabPointHandRight" type="Marker3D"]
|
||||
visible = false
|
||||
script = ExtResource("1")
|
||||
hand = 1
|
||||
@@ -0,0 +1,17 @@
|
||||
@tool
|
||||
class_name XRToolsGrabPointRedirect
|
||||
extends XRToolsGrabPoint
|
||||
|
||||
|
||||
## Grab point to redirect grabbing to
|
||||
@export var target : XRToolsGrabPoint
|
||||
|
||||
|
||||
## Evaluate fitness of the proposed grab, with 0.0 for not allowed.
|
||||
func can_grab(grabber : Node3D, current : XRToolsGrabPoint) -> float:
|
||||
# Fail if no target
|
||||
if not is_instance_valid(target):
|
||||
return 0.0
|
||||
|
||||
# Consult the target
|
||||
return target.can_grab(grabber, current)
|
||||
@@ -0,0 +1 @@
|
||||
uid://1vp1ger1vuws
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://ca3daqmpo0tua"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_redirect.gd" id="1_vyuch"]
|
||||
|
||||
[node name="GrabPointRedirect" type="Marker3D"]
|
||||
script = ExtResource("1_vyuch")
|
||||
@@ -0,0 +1,49 @@
|
||||
@tool
|
||||
class_name XRToolsGrabPointSnap
|
||||
extends XRToolsGrabPoint
|
||||
|
||||
|
||||
## XR Tools Grab Point Snap Script
|
||||
##
|
||||
## This script allows specifying a grab point for snap zones. It supports
|
||||
## group-filters if different points are required for different snap zones.
|
||||
|
||||
|
||||
## Require grab-by to be in the specified group
|
||||
@export var require_group : String = ""
|
||||
|
||||
## Deny grab-by if in the specified group
|
||||
@export var exclude_group : String = ""
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
# Add a Position3D child to help editor visibility
|
||||
if Engine.is_editor_hint():
|
||||
add_child(Marker3D.new())
|
||||
|
||||
|
||||
## Evaluate fitness of the proposed grab, with 0.0 for not allowed.
|
||||
func can_grab(grabber : Node3D, current : XRToolsGrabPoint) -> float:
|
||||
# Skip if not enabled or current grab
|
||||
if not enabled or current:
|
||||
return 0.0
|
||||
|
||||
# Ensure the pickup is valid
|
||||
if not is_instance_valid(grabber):
|
||||
return 0.0
|
||||
|
||||
# Ensure the grabber is a snap-zone
|
||||
if not grabber is XRToolsSnapZone:
|
||||
return 0.0
|
||||
|
||||
# Refuse if the grabber is not in the required group
|
||||
if not require_group.is_empty() and not grabber.is_in_group(require_group):
|
||||
return 0.0
|
||||
|
||||
# Refuse if the grabber is in the excluded group
|
||||
if not exclude_group.is_empty() and grabber.is_in_group(exclude_group):
|
||||
return 0.0
|
||||
|
||||
# Return the distance-weighted fitness
|
||||
return _weight(grabber)
|
||||
@@ -0,0 +1 @@
|
||||
uid://fbex26bgf88h
|
||||
@@ -0,0 +1,7 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dh8grd7s3n8kg"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_snap.gd" id="1"]
|
||||
|
||||
[node name="GrabPointSnap" type="Marker3D"]
|
||||
visible = false
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,32 @@
|
||||
class_name Grabber
|
||||
|
||||
|
||||
## Grabber Class
|
||||
##
|
||||
## This class contains relevant information for a grabber including any
|
||||
## assocated pickup, controller, and hand nodes.
|
||||
|
||||
|
||||
## Grabber node
|
||||
var by : Node3D
|
||||
|
||||
## Pickup associated with the grabber
|
||||
var pickup : XRToolsFunctionPickup
|
||||
|
||||
## Controller associated with the grabber
|
||||
var controller : XRController3D
|
||||
|
||||
## Hand associated with the grabber
|
||||
var hand : XRToolsHand
|
||||
|
||||
## Collision hand associated with the grabber
|
||||
var collision_hand : XRToolsCollisionHand
|
||||
|
||||
|
||||
## Initialize the grabber
|
||||
func _init(p_by : Node3D) -> void:
|
||||
by = p_by
|
||||
pickup = p_by as XRToolsFunctionPickup
|
||||
controller = pickup.get_controller() if pickup else null
|
||||
hand = XRToolsHand.find_instance(controller)
|
||||
collision_hand = XRToolsCollisionHand.find_instance(controller)
|
||||
@@ -0,0 +1 @@
|
||||
uid://c25o68ugepdhc
|
||||
Reference in New Issue
Block a user