From 19f089edc3d6a0024a4459e3d4b2b7619d42cdf1 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Tue, 10 Dec 2024 15:11:46 +1100 Subject: [PATCH] Add weighted logic to collision hands (#695) * Add weighted logic to collision hands * Added logic to properly handle movement and teleport impact on collision hands --- .../movement_desktop_flight.gd | 2 +- .../functions/function_pickup.gd | 5 + .../functions/movement_flight.gd | 2 +- .../functions/movement_glide.gd | 2 +- .../functions/movement_grapple.gd | 2 +- .../godot-xr-tools/functions/movement_turn.gd | 1 + .../functions/movement_world_grab.gd | 2 +- addons/godot-xr-tools/hands/collision_hand.gd | 108 +++++++++++++++-- .../scenes/collision/collision_hand.tscn | 3 +- .../scenes/collision/collision_hand_left.tscn | 2 +- .../collision/collision_hand_right.tscn | 2 +- .../objects/force_body/force_body.gd | 83 +++++++++++++ .../objects/grab_points/grab.gd | 7 +- .../objects/grab_points/grab_driver.gd | 22 +++- .../objects/grab_points/grabber.gd | 6 +- addons/godot-xr-tools/player/player_body.gd | 58 +++++++-- .../godot-xr-tools/player/poke/poke_body.gd | 31 +++++ .../models/scenes/sniper_rifle.tscn | 4 +- .../models/sniper_rifle/firearm_trigger.gd | 2 +- assets/digitaln8m4r3/scripts/firearm_bolt.gd | 7 +- assets/digitaln8m4r3/scripts/firearm_slide.gd | 26 ++-- .../meshes/control_pad/control_pad_display.gd | 4 +- .../control_pad/control_pad_location.gd | 4 +- .../picatinny_rail/picatinny_30.glb.import | 2 - .../materials/ghost_hand.tres | 2 +- scenes/main_menu/main_menu_level.gd | 2 +- .../pickable_demo/materials/ghost_hands.tres | 7 ++ scenes/pickable_demo/objects/grab_ball.tscn | 7 +- scenes/pickable_demo/objects/hammer.tscn | 1 + .../objects/picatinny_scope.tscn | 1 + scenes/pickable_demo/objects/teacup.tscn | 1 + scenes/pickable_demo/pickable_demo.gd | 16 +++ scenes/pickable_demo/pickable_demo.tscn | 112 +++++++++++++----- 33 files changed, 447 insertions(+), 89 deletions(-) create mode 100644 scenes/pickable_demo/materials/ghost_hands.tres create mode 100644 scenes/pickable_demo/pickable_demo.gd diff --git a/addons/godot-xr-tools/desktop-support/movement_desktop_flight.gd b/addons/godot-xr-tools/desktop-support/movement_desktop_flight.gd index 2b0a079c..13e623df 100644 --- a/addons/godot-xr-tools/desktop-support/movement_desktop_flight.gd +++ b/addons/godot-xr-tools/desktop-support/movement_desktop_flight.gd @@ -139,7 +139,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo # If exclusive then perform the exclusive move-and-slide if exclusive: - player_body.velocity = player_body.move_body(flight_velocity) + player_body.velocity = player_body.move_player(flight_velocity) return true # Update velocity and return for additional effects diff --git a/addons/godot-xr-tools/functions/function_pickup.gd b/addons/godot-xr-tools/functions/function_pickup.gd index db4d1d13..49af7f95 100644 --- a/addons/godot-xr-tools/functions/function_pickup.gd +++ b/addons/godot-xr-tools/functions/function_pickup.gd @@ -388,6 +388,11 @@ func drop_object() -> void: _velocity_averager.linear_velocity() * impulse_factor, _velocity_averager.angular_velocity()) picked_up_object = null + + if _collision_hand: + # Reset the held weight + _collision_hand.set_held_weight(0.0) + emit_signal("has_dropped") diff --git a/addons/godot-xr-tools/functions/movement_flight.gd b/addons/godot-xr-tools/functions/movement_flight.gd index 9ffa9a10..49bc9e9e 100644 --- a/addons/godot-xr-tools/functions/movement_flight.gd +++ b/addons/godot-xr-tools/functions/movement_flight.gd @@ -186,7 +186,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo # If exclusive then perform the exclusive move-and-slide if exclusive: - player_body.velocity = player_body.move_body(flight_velocity) + player_body.velocity = player_body.move_player(flight_velocity) return true # Update velocity and return for additional effects diff --git a/addons/godot-xr-tools/functions/movement_glide.gd b/addons/godot-xr-tools/functions/movement_glide.gd index e77b1a24..bff2ba9b 100644 --- a/addons/godot-xr-tools/functions/movement_glide.gd +++ b/addons/godot-xr-tools/functions/movement_glide.gd @@ -190,7 +190,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo # Perform the glide var glide_velocity := horizontal_velocity + vertical_velocity * player_body.up_gravity - player_body.velocity = player_body.move_body(glide_velocity) + player_body.velocity = player_body.move_player(glide_velocity) # Report exclusive motion performed (to bypass gravity) return true diff --git a/addons/godot-xr-tools/functions/movement_grapple.gd b/addons/godot-xr-tools/functions/movement_grapple.gd index bc90490f..37e47736 100644 --- a/addons/godot-xr-tools/functions/movement_grapple.gd +++ b/addons/godot-xr-tools/functions/movement_grapple.gd @@ -191,7 +191,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo player_body.velocity *= 1.0 - friction * delta # Perform exclusive movement as we have dealt with gravity - player_body.velocity = player_body.move_body(player_body.velocity) + player_body.velocity = player_body.move_player(player_body.velocity) return true diff --git a/addons/godot-xr-tools/functions/movement_turn.gd b/addons/godot-xr-tools/functions/movement_turn.gd index b64b601e..551ad698 100644 --- a/addons/godot-xr-tools/functions/movement_turn.gd +++ b/addons/godot-xr-tools/functions/movement_turn.gd @@ -83,6 +83,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, _disabled: b # Turn one step in the requested direction if step_turn_delay != 0.0: _turn_step = step_turn_delay + player_body.rotate_player(deg_to_rad(step_turn_angle) * sign(left_right)) diff --git a/addons/godot-xr-tools/functions/movement_world_grab.gd b/addons/godot-xr-tools/functions/movement_world_grab.gd index 45976490..ea6b144a 100644 --- a/addons/godot-xr-tools/functions/movement_world_grab.gd +++ b/addons/godot-xr-tools/functions/movement_world_grab.gd @@ -139,7 +139,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo # Move the player by the offset var old_position := player_body.global_position - player_body.move_body(-offset / delta) + player_body.move_player(-offset / delta) player_body.velocity = Vector3.ZERO #player_body.move_and_collide(-offset) diff --git a/addons/godot-xr-tools/hands/collision_hand.gd b/addons/godot-xr-tools/hands/collision_hand.gd index 92cd1532..223b8aa6 100644 --- a/addons/godot-xr-tools/hands/collision_hand.gd +++ b/addons/godot-xr-tools/hands/collision_hand.gd @@ -9,6 +9,8 @@ extends XRToolsForceBody ## its ancestor [XRController3D], and can act as a container for hand models ## and pickup functions. +# We reached our teleport distance +signal max_distance_reached ## Modes for collision hand enum CollisionHandMode { @@ -39,7 +41,6 @@ const ORIENT_DISPLACEMENT := 0.05 # Distance to teleport hands const TELEPORT_DISTANCE := 1.0 - ## Controls the hand collision mode @export var mode : CollisionHandMode = CollisionHandMode.COLLIDE @@ -68,6 +69,15 @@ const TELEPORT_DISTANCE := 1.0 notify_property_list_changed() + +## Minimum force we can exert on a picked up object +@export_range(1.0, 1000.0, 0.1, "suffix:N") var min_pickup_force : float = 15.0 + +## Force we exert on a picked up object when hand is at maximum distance +## before letting go. +@export_range(1.0, 1000.0, 0.1, "suffix:N") var max_pickup_force : float = 300.0 + + # Controller to target (if no target overrides) var _controller : XRController3D @@ -81,6 +91,11 @@ var _target : Node3D var _palm_collision_shape : CollisionShape3D var _digit_collision_shapes : Dictionary +# The weight held by this hand +var _held_weight : float = 0.0 + +# Movement on last frame +var _last_movement : Vector3 = Vector3() ## Target-override class class TargetOverride: @@ -96,6 +111,11 @@ class TargetOverride: priority = p +# Update the weight attributed to this hand (updated from pickable system). +func set_held_weight(new_weight): + _held_weight = new_weight + + # Add support for is_xr_class on XRTools classes func is_xr_class(name : String) -> bool: return name == "XRToolsCollisionHand" @@ -148,6 +168,12 @@ func _ready(): process_physics_priority = -90 sync_to_physics = false + # Connect to player body signals (if applicable) + var player_body = XRToolsPlayerBody.find_instance(self) + if player_body: + player_body.player_moved.connect(_on_player_moved) + player_body.player_teleported.connect(_on_player_teleported) + # Populate nodes _controller = XRTools.find_xr_ancestor(self, "*", "XRController3D") @@ -156,14 +182,17 @@ func _ready(): # Handle physics processing -func _physics_process(_delta): +func _physics_process(delta): # Do not process if in the editor if Engine.is_editor_hint(): return + var current_position = global_position + # Move to the current target - _move_to_target() + _move_to_target(delta) + _last_movement = global_position - current_position ## This function adds a target override. The collision hand will attempt to ## move to the highest priority target, or the [XRController3D] if no override @@ -227,7 +256,7 @@ static func find_right(node : Node) -> XRToolsCollisionHand: # This function moves the collision hand to the target node. -func _move_to_target(): +func _move_to_target(delta): # Handle DISABLED or no target if mode == CollisionHandMode.DISABLED or not _target: return @@ -239,12 +268,77 @@ func _move_to_target(): # Handle too far from target if global_position.distance_to(_target.global_position) > TELEPORT_DISTANCE: + print("max distance reached") + max_distance_reached.emit() + global_transform = _target.global_transform return - # Orient the hand then move - global_transform.basis = _target.global_transform.basis - move_and_slide(_target.global_position - global_position) + # Orient the hand + rotate_and_collide(_target.global_basis) + + # Adjust target position if we're holding something + var target_movement : Vector3 = _target.global_position - global_position + if _held_weight > 0.0: + var gravity_state := PhysicsServer3D.body_get_direct_state(get_rid()) + var gravity = gravity_state.total_gravity * delta + + # Calculate the movement of our held object if we weren't holding it + var base_movement : Vector3 = _last_movement * 0.2 + gravity + + # How much movement is left until we reach our target + var remaining_movement = target_movement - base_movement + + # The below is an approximation as we're not taking the logarithmic + # nature of force acceleration into account for simplicitiy. + + # Distance over time gives our needed acceleration which + # gives us the force needed on the object to move it to our + # target destination. + # But dividing and then multiplying over delta and mass is wasteful. + var needed_distance = remaining_movement.length() + + # Force we can exert on the object + var force = min_pickup_force + \ + (target_movement.length() * (max_pickup_force-min_pickup_force) / TELEPORT_DISTANCE) + + # How much can we move our object? + var possible_distance = delta * force / _held_weight + if possible_distance < needed_distance: + # We can't make our distance? adjust our movement! + remaining_movement *= (possible_distance / needed_distance) + target_movement = base_movement + remaining_movement + + # And move + move_and_slide(target_movement) + force_update_transform() + + +# If our player moved, attempt to move our hand but ignoring weight. +func _on_player_moved(delta_transform : Transform3D): + if mode == CollisionHandMode.DISABLED: + return + + if mode == CollisionHandMode.TELEPORT: + _on_player_teleported(delta_transform) + return + + var target : Transform3D = delta_transform * global_transform + + # Rotate + rotate_and_collide(target.basis) + + # And attempt to move + move_and_slide(target.origin - global_position) + force_update_transform() + + +# If our player teleported, just move. +func _on_player_teleported(delta_transform : Transform3D): + if mode == CollisionHandMode.DISABLED: + return + + global_transform = delta_transform * global_transform force_update_transform() diff --git a/addons/godot-xr-tools/hands/scenes/collision/collision_hand.tscn b/addons/godot-xr-tools/hands/scenes/collision/collision_hand.tscn index b6cf12f4..b884f802 100644 --- a/addons/godot-xr-tools/hands/scenes/collision/collision_hand.tscn +++ b/addons/godot-xr-tools/hands/scenes/collision/collision_hand.tscn @@ -4,6 +4,7 @@ [node name="XRToolsCollisionHand" type="AnimatableBody3D"] collision_layer = 131072 -collision_mask = 327711 +collision_mask = 262175 sync_to_physics = false script = ExtResource("1_vdcct") +max_pickup_force = 400.0 diff --git a/addons/godot-xr-tools/hands/scenes/collision/collision_hand_left.tscn b/addons/godot-xr-tools/hands/scenes/collision/collision_hand_left.tscn index cb8cee04..61759009 100644 --- a/addons/godot-xr-tools/hands/scenes/collision/collision_hand_left.tscn +++ b/addons/godot-xr-tools/hands/scenes/collision/collision_hand_left.tscn @@ -5,7 +5,7 @@ [node name="CollisionHandLeft" type="AnimatableBody3D"] collision_layer = 131072 -collision_mask = 327711 +collision_mask = 262175 sync_to_physics = false script = ExtResource("1_t5acd") diff --git a/addons/godot-xr-tools/hands/scenes/collision/collision_hand_right.tscn b/addons/godot-xr-tools/hands/scenes/collision/collision_hand_right.tscn index 57faa211..64ddfbd0 100644 --- a/addons/godot-xr-tools/hands/scenes/collision/collision_hand_right.tscn +++ b/addons/godot-xr-tools/hands/scenes/collision/collision_hand_right.tscn @@ -5,7 +5,7 @@ [node name="CollisionHandRight" type="AnimatableBody3D"] collision_layer = 131072 -collision_mask = 327711 +collision_mask = 262175 sync_to_physics = false script = ExtResource("1_so3hf") diff --git a/addons/godot-xr-tools/objects/force_body/force_body.gd b/addons/godot-xr-tools/objects/force_body/force_body.gd index 7d685847..49a10079 100644 --- a/addons/godot-xr-tools/objects/force_body/force_body.gd +++ b/addons/godot-xr-tools/objects/force_body/force_body.gd @@ -97,3 +97,86 @@ func move_and_slide(move : Vector3) -> ForceBodyCollision: # Return the last collision data return ret + + +## Attempts to rotate our object until it collides +func rotate_and_collide( \ + target_global_basis : Basis, \ + step_angle : float = deg_to_rad(5.0) \ + ) -> ForceBodyCollision: + # Make sure this is off or weird shit happens... + sync_to_physics = false + + var ret : ForceBodyCollision = null + + var space = PhysicsServer3D.body_get_space(get_rid()) + var direct_state = PhysicsServer3D.space_get_direct_state(space) + + # We don't seem to have a rotational movement query for collisions, + # so best we can do is to rotate in steps and test + var from_quat : Quaternion = Quaternion(global_basis) + var to_quat : Quaternion = Quaternion(target_global_basis) + var angle : float = from_quat.angle_to(to_quat) + var steps : float = ceil(angle / step_angle) + + # Convert collision exceptions to a RID array + var exception_rids : Array[RID] + for collision_exception in get_collision_exceptions(): + exception_rids.push_back(collision_exception.get_rid()) + + # Prevent collisions with ourselves + exception_rids.push_back(get_rid()) + + # Find our shape ids + var shape_rids : Array[RID] + for node in get_children(true): + if node is CollisionShape3D: + var col_shape : CollisionShape3D = node + if not col_shape.disabled: + shape_rids.push_back(col_shape.shape.get_rid()) + + # Our physics query + var query : PhysicsShapeQueryParameters3D = PhysicsShapeQueryParameters3D.new() + query.collide_with_areas = false + query.collide_with_bodies = true + query.collision_mask = collision_mask + query.exclude = exception_rids + + # Check our collisions + var step : float = 0.0 + var new_quat : Quaternion = from_quat + var t = global_transform + while step < steps and not ret: + step += 1.0 + + var test_quat : Quaternion = from_quat.slerp(to_quat, step / steps) + t.basis = Basis(test_quat) + query.transform = t + + for rid in shape_rids: + query.shape_rid = rid + var collision = direct_state.get_rest_info(query) + if not collision.is_empty(): + ret = ForceBodyCollision.new() + ret.collider = instance_from_id(collision["collider_id"]) + ret.position = collision["point"] + ret.normal = collision["normal"] + + # TODO May need to see about applying a rotational force + # if pushbodies is true + + break + + if not ret: + # No collision, we can rotate this far! + new_quat = test_quat + + # Update our rotation to our last successful rotation + global_basis = Basis(new_quat) + + # Return the last collision data + return ret + + +func _ready(): + process_physics_priority = -90 diff --git a/addons/godot-xr-tools/objects/grab_points/grab.gd b/addons/godot-xr-tools/objects/grab_points/grab.gd index d749b35a..4b9aaffa 100644 --- a/addons/godot-xr-tools/objects/grab_points/grab.gd +++ b/addons/godot-xr-tools/objects/grab_points/grab.gd @@ -78,6 +78,7 @@ func _init( # Apply collision exceptions if collision_hand: + collision_hand.max_distance_reached.connect(_on_max_distance_reached) _add_collision_exceptions(what) @@ -154,6 +155,11 @@ func release() -> void: what.released.emit(what, by) +# Hand has moved too far away from object, can no longer hold on to it. +func _on_max_distance_reached() -> void: + pickup.drop_object() + + # Set hand-pose overrides func _set_hand_pose() -> void: # Skip if not hand @@ -192,7 +198,6 @@ func _add_collision_exceptions(from : Node): # If this is a physics body, add an exception if from is PhysicsBody3D: - print_debug("Add collision exception for ", from.name) # Make sure we don't collide with what we're holding _collision_exceptions.push_back(from) collision_hand.add_collision_exception_with(from) diff --git a/addons/godot-xr-tools/objects/grab_points/grab_driver.gd b/addons/godot-xr-tools/objects/grab_points/grab_driver.gd index 3221ffbf..a579622f 100644 --- a/addons/godot-xr-tools/objects/grab_points/grab_driver.gd +++ b/addons/godot-xr-tools/objects/grab_points/grab_driver.gd @@ -30,7 +30,6 @@ 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 @@ -89,6 +88,7 @@ func _physics_process(delta : float) -> void: else: # Lerp completed state = GrabState.SNAP + _update_weight() if primary: primary.set_arrived() if secondary: secondary.set_arrived() @@ -112,6 +112,7 @@ func add_grab(p_grab : Grab) -> void: # If snapped then report arrived at the new grab if state == GrabState.SNAP: + _update_weight() p_grab.set_arrived() @@ -138,6 +139,9 @@ func remove_grab(p_grab : Grab) -> void: print_verbose("%s> %s (secondary) released" % [target.name, p_grab.by.name]) secondary = null + if state == GrabState.SNAP: + _update_weight() + # Discard the driver func discard(): @@ -204,6 +208,8 @@ static func create_snap( p_target.get_parent().add_child(driver) driver.remote_path = driver.get_path_to(p_target) + driver._update_weight() + # Return the driver return driver @@ -214,3 +220,17 @@ static func _vote(a : float, b : float) -> float: return 0.0 return b / (a + b) + + +# Update the weight on collision hands +func _update_weight(): + if primary: + var weight : float = target.mass + if secondary: + # Each hand carries half the weight + weight = weight / 2.0 + if secondary.collision_hand: + secondary.collision_hand.set_held_weight(weight) + + if primary.collision_hand: + primary.collision_hand.set_held_weight(weight) diff --git a/addons/godot-xr-tools/objects/grab_points/grabber.gd b/addons/godot-xr-tools/objects/grab_points/grabber.gd index 2576ca65..0474bdd4 100644 --- a/addons/godot-xr-tools/objects/grab_points/grabber.gd +++ b/addons/godot-xr-tools/objects/grab_points/grabber.gd @@ -22,11 +22,11 @@ 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) + if controller: + hand = XRToolsHand.find_instance(controller) + collision_hand = XRToolsCollisionHand.find_instance(controller) diff --git a/addons/godot-xr-tools/player/player_body.gd b/addons/godot-xr-tools/player/player_body.gd index a60a5f31..8674cf67 100644 --- a/addons/godot-xr-tools/player/player_body.gd +++ b/addons/godot-xr-tools/player/player_body.gd @@ -20,15 +20,18 @@ extends CharacterBody3D ## track the players movement. -## Signal emitted when the player jumps +## Signal emitted when the player jumps. signal player_jumped() -## Signal emitted when the player teleports -signal player_teleported() +## Signal emitted when the player teleports. +signal player_teleported(delta_transform) -## Signal emitted when the player bounces +## Signal emitted when the player bounces. signal player_bounced(collider, magnitude) +## Signal emitted when the player has moved (excluding teleport). +## This only captures movement handled by the player body logic. +signal player_moved(delta_transform) ## Enumeration indicating when ground control can be used enum GroundControl { @@ -163,6 +166,9 @@ var _collision_node : CollisionShape3D # Player head shape cast var _head_shape_cast : ShapeCast3D +# True while we're handling physics +var _in_physics_movement : bool = false + ## XROrigin3D node @onready var origin_node : XROrigin3D = XRHelpers.get_xr_origin(self) @@ -262,6 +268,12 @@ func _physics_process(delta: float): set_physics_process(false) return + # We're handling physics right now + _in_physics_movement = true + + # Remember where we are now + var current_transform : Transform3D = global_transform + # Calculate the players "up" direction and plane up_player = origin_node.global_transform.basis.y @@ -325,11 +337,21 @@ func _physics_process(delta: float): # Orient the player towards (potentially modified) gravity slew_up(-gravity.normalized(), 5.0 * delta) + # If we moved our player, emit signal + var delta_transform : Transform3D = global_transform * current_transform.inverse() + if delta_transform.origin.length() > 0.001: + player_moved.emit(delta_transform) -## Teleport the player body + # And we're done! + _in_physics_movement = false + +## Teleport the player body. +## This moves the player without checking for collisions. func teleport(target : Transform3D) -> void: + var inv_global_transform : Transform3D = global_transform.inverse() + # Get the player-to-origin transform - var player_to_origin = global_transform.inverse() * origin_node.global_transform + var player_to_origin : Transform3D = inv_global_transform * origin_node.global_transform # Set the player global_transform = target @@ -338,7 +360,7 @@ func teleport(target : Transform3D) -> void: origin_node.global_transform = target * player_to_origin # Report the player teleported - player_teleported.emit() + player_teleported.emit(target * inv_global_transform) ## Request a jump @@ -371,15 +393,28 @@ func request_jump(skip_jump_velocity := false): # Report the jump emit_signal("player_jumped") + ## This method moves the players body using the provided velocity. Movement ## providers may use this function if they are exclusively driving the player. -func move_body(p_velocity: Vector3) -> Vector3: +func move_player(p_velocity: Vector3) -> Vector3: velocity = p_velocity max_slides = 4 up_direction = ground_vector + # Get the player body location before we apply our movement. + var transform_before_movement : Transform3D = global_transform + move_and_slide() + if not _in_physics_movement: + # Apply the player-body movement to the XR origin + var movement := global_transform.origin - transform_before_movement.origin + origin_node.global_transform.origin += movement + + var delta_transform : Transform3D = global_transform * transform_before_movement.inverse() + if delta_transform.origin.length() > 0.001: + player_moved.emit(delta_transform) + # Check if we collided with rigid bodies and apply impulses to them to move them out of the way if push_rigid_bodies: for idx in range(get_slide_collision_count()): @@ -410,6 +445,8 @@ func move_body(p_velocity: Vector3) -> Vector3: ## This method rotates the player by rotating the [XROrigin3D] around the camera. func rotate_player(angle: float): + var inv_global_transform : Transform3D = global_transform.inverse() + var t1 := Transform3D() var t2 := Transform3D() var rot := Transform3D() @@ -419,6 +456,9 @@ func rotate_player(angle: float): rot = rot.rotated(Vector3.DOWN, angle) origin_node.transform = (origin_node.transform * t2 * rot * t1).orthonormalized() + if not _in_physics_movement: + player_moved.emit(global_transform * inv_global_transform) + ## This method slews the players up vector by rotating the [ARVROrigin] around ## the players feet. func slew_up(up: Vector3, slew: float) -> void: @@ -701,7 +741,7 @@ func _apply_velocity_and_control(delta: float): local_velocity = horizontal_velocity + vertical_velocity # Move the player body with the desired velocity - velocity = move_body(local_velocity + ground_velocity) + velocity = move_player(local_velocity + ground_velocity) # Apply ground-friction after the move if _can_apply_ground_control() and ground_control_velocity.length() < 0.1: diff --git a/addons/godot-xr-tools/player/poke/poke_body.gd b/addons/godot-xr-tools/player/poke/poke_body.gd index b3666aec..13c24de4 100644 --- a/addons/godot-xr-tools/player/poke/poke_body.gd +++ b/addons/godot-xr-tools/player/poke/poke_body.gd @@ -25,6 +25,18 @@ func is_xr_class(name : String) -> bool: return name == "XRToolsPokeBody" or super(name) +func _ready(): + # Do not initialise if in the editor + if Engine.is_editor_hint(): + return + + # Connect to player body signals (if applicable) + var player_body = XRToolsPlayerBody.find_instance(self) + if player_body: + player_body.player_moved.connect(_on_player_moved) + player_body.player_teleported.connect(_on_player_teleported) + + # Try moving to the parent Poke node func _physics_process(_delta): # Do not process if in the editor @@ -52,3 +64,22 @@ func _physics_process(_delta): # Report when we start touching a new object if _contact and _contact != old_contact: body_contact_start.emit(_contact) + + +# If our player moved, attempt to move our poke. +func _on_player_moved(delta_transform : Transform3D): + var target : Transform3D = delta_transform * global_transform + + # Rotate + global_basis = target.basis + + # And attempt to move (we'll detect contact change in physics process). + move_and_slide(target.origin - global_position) + + force_update_transform() + + +# If our player teleported, just move. +func _on_player_teleported(delta_transform : Transform3D): + global_transform = delta_transform * global_transform + force_update_transform() diff --git a/assets/3dmodelscc0/models/scenes/sniper_rifle.tscn b/assets/3dmodelscc0/models/scenes/sniper_rifle.tscn index 7c743fb9..11fb949c 100644 --- a/assets/3dmodelscc0/models/scenes/sniper_rifle.tscn +++ b/assets/3dmodelscc0/models/scenes/sniper_rifle.tscn @@ -112,6 +112,7 @@ radius = 0.001 [node name="SniperRifle" instance=ExtResource("1_lpv7q")] collision_mask = 7 +mass = 10.0 script = ExtResource("2_bdnea") second_hand_grab = 2 @@ -175,12 +176,10 @@ value = Vector3(0, 0, 75) [node name="GrabPointHandleLeft" parent="sniper_rifle/FirearmSlide/SliderBody/Bolt" index="0" instance=ExtResource("2_x4cgt")] transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0, -0.0359677, -0.0150545) -visible = true hand_pose = SubResource("Resource_aoud0") [node name="GrabPointHandleRight" parent="sniper_rifle/FirearmSlide/SliderBody/Bolt" index="1" instance=ExtResource("5_sjb82")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.0149273) -visible = true hand_pose = SubResource("Resource_gyywm") [node name="HandleOrigin" type="Node3D" parent="sniper_rifle/FirearmSlide" index="1"] @@ -223,7 +222,6 @@ hand_pose = SubResource("Resource_kscym") [node name="GrabPointForestockLeft" parent="." index="6" instance=ExtResource("2_x4cgt")] transform = Transform3D(-2.50718e-08, -0.573576, -0.819152, 0.965926, 0.212012, -0.148453, 0.258819, -0.79124, 0.554032, 0.0292044, 0.0294211, -0.107) -visible = true hand_pose = SubResource("Resource_tbrsh") drive_position = 0.0 drive_angle = 0.0 diff --git a/assets/3dmodelscc0/models/sniper_rifle/firearm_trigger.gd b/assets/3dmodelscc0/models/sniper_rifle/firearm_trigger.gd index 54c1de4c..9460ee62 100644 --- a/assets/3dmodelscc0/models/sniper_rifle/firearm_trigger.gd +++ b/assets/3dmodelscc0/models/sniper_rifle/firearm_trigger.gd @@ -30,7 +30,7 @@ func _ready() -> void: for handle_grabpoint in handle_grabpoints: handle_grabpoint.enabled = false -func _physics_process(delta): +func _physics_process(_delta): if is_instance_valid(_parent): # toggle handle grabpoints if parent got grabbed/released if _parent.get_picked_up_by(): diff --git a/assets/digitaln8m4r3/scripts/firearm_bolt.gd b/assets/digitaln8m4r3/scripts/firearm_bolt.gd index 4d40db8d..5f41d0ba 100644 --- a/assets/digitaln8m4r3/scripts/firearm_bolt.gd +++ b/assets/digitaln8m4r3/scripts/firearm_bolt.gd @@ -2,8 +2,6 @@ class_name XRFirearmBolt extends MeshInstance3D -@export var _owner : XRToolsPickable - @export var _handle : XRToolsInteractableHandle @export var _slide : XRFirearmSlide @@ -38,7 +36,7 @@ func _on_released(_pickable, _by) -> void: func _update_controller_signals() -> void: # Find the primary controller holding the firearm var controller := _handle.get_picked_up_by_controller() - var grab_point := _handle.get_active_grab_point() as XRToolsGrabPointHand + #var grab_point := _handle.get_active_grab_point() as XRToolsGrabPointHand #if not grab_point or grab_point.handle != "Grip": # controller = null @@ -69,6 +67,7 @@ func _on_controller_trigger_released(trigger_button : String): return reset_rotation() + + func reset_rotation(): rotation_degrees = Vector3(0,0,0) - diff --git a/assets/digitaln8m4r3/scripts/firearm_slide.gd b/assets/digitaln8m4r3/scripts/firearm_slide.gd index db870004..893545b4 100644 --- a/assets/digitaln8m4r3/scripts/firearm_slide.gd +++ b/assets/digitaln8m4r3/scripts/firearm_slide.gd @@ -75,17 +75,17 @@ func _process(_delta: float) -> void: # Move the slider to the specified position -func move_slider(position: float) -> void: +func move_slider(new_position: float) -> void: # Do the slider move - position = _do_move_slider(position) - if position == slider_position: + new_position = _do_move_slider(new_position) + if new_position == slider_position: return # Update the current position - slider_position = position + slider_position = new_position # Emit the moved signal - emit_signal("firearm_slider_moved", position) + emit_signal("firearm_slider_moved", new_position) # Handle release of slider @@ -95,19 +95,19 @@ func _on_slider_released(_interactable: XRFirearmSlide): # Called when the slider position is set externally -func _set_slider_position(position: float) -> void: - position = _do_move_slider(position) - slider_position = position +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(position: float) -> float: +func _do_move_slider(new_position: float) -> float: # Apply slider limits - position = clamp(position, slider_start, slider_end) + new_position = clamp(new_position, slider_start, slider_end) # Move if necessary - if position != slider_position: - transform.origin.z = position + if new_position != slider_position: + transform.origin.z = new_position # Return the updated position - return position + return new_position diff --git a/assets/meshes/control_pad/control_pad_display.gd b/assets/meshes/control_pad/control_pad_display.gd index a18f8d78..8ae74b72 100644 --- a/assets/meshes/control_pad/control_pad_display.gd +++ b/assets/meshes/control_pad/control_pad_display.gd @@ -71,5 +71,5 @@ func _on_quit_pressed(): # Called by the tweening to change the world scale -func _set_world_scale(scale : float) -> void: - XRServer.world_scale = scale +func _set_world_scale(new_scale : float) -> void: + XRServer.world_scale = new_scale diff --git a/assets/meshes/control_pad/control_pad_location.gd b/assets/meshes/control_pad/control_pad_location.gd index 42df3fed..482a18e4 100644 --- a/assets/meshes/control_pad/control_pad_location.gd +++ b/assets/meshes/control_pad/control_pad_location.gd @@ -24,9 +24,9 @@ func _ready(): # Handle world scale changing -func _on_hand_scale_changed(scale : float) -> void: +func _on_hand_scale_changed(new_scale : float) -> void: # Scale ourselves (and our children) - transform = _transform.scaled(Vector3.ONE * scale) + transform = _transform.scaled(Vector3.ONE * new_scale) ## Find a ControlPadLocation related to the specified node diff --git a/assets/meshes/picatinny_rail/picatinny_30.glb.import b/assets/meshes/picatinny_rail/picatinny_30.glb.import index c7960e35..e96341c3 100644 --- a/assets/meshes/picatinny_rail/picatinny_30.glb.import +++ b/assets/meshes/picatinny_rail/picatinny_30.glb.import @@ -17,7 +17,6 @@ nodes/root_type="Node3D" nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true @@ -29,7 +28,6 @@ animation/import=false animation/fps=30 animation/trimming=false animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false import_script/path="" _subresources={} gltf/naming_version=0 diff --git a/scenes/climbing_gliding_demo/materials/ghost_hand.tres b/scenes/climbing_gliding_demo/materials/ghost_hand.tres index a6bfb5b0..f86644ad 100644 --- a/scenes/climbing_gliding_demo/materials/ghost_hand.tres +++ b/scenes/climbing_gliding_demo/materials/ghost_hand.tres @@ -1,6 +1,6 @@ [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cf6y1af3ouutt"] -[ext_resource type="Material" path="res://addons/godot-xr-tools/hands/materials/glove_caucasian_green_camo.tres" id="1_3o4sh"] +[ext_resource type="Material" uid="uid://f2uhcqq8s2jx" path="res://addons/godot-xr-tools/hands/materials/glove_caucasian_green_camo.tres" id="1_3o4sh"] [resource] render_priority = -1 diff --git a/scenes/main_menu/main_menu_level.gd b/scenes/main_menu/main_menu_level.gd index ac8b078d..cddef783 100644 --- a/scenes/main_menu/main_menu_level.gd +++ b/scenes/main_menu/main_menu_level.gd @@ -38,5 +38,5 @@ func _on_Demos_child_exiting_tree(_node): _update_demo_positions() -func _on_settings_ui_player_height_changed(new_height): +func _on_settings_ui_player_height_changed(_new_height): $XROrigin3D/PlayerBody.calibrate_player_height() diff --git a/scenes/pickable_demo/materials/ghost_hands.tres b/scenes/pickable_demo/materials/ghost_hands.tres new file mode 100644 index 00000000..917b7dce --- /dev/null +++ b/scenes/pickable_demo/materials/ghost_hands.tres @@ -0,0 +1,7 @@ +[gd_resource type="StandardMaterial3D" format=3 uid="uid://c5jkrtp4eipf4"] + +[resource] +transparency = 1 +no_depth_test = true +shading_mode = 0 +albedo_color = Color(0, 1, 1, 0.25098) diff --git a/scenes/pickable_demo/objects/grab_ball.tscn b/scenes/pickable_demo/objects/grab_ball.tscn index f1c6393d..3bf5a60e 100644 --- a/scenes/pickable_demo/objects/grab_ball.tscn +++ b/scenes/pickable_demo/objects/grab_ball.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=10 format=3 uid="uid://clta811tt773x"] +[gd_scene load_steps=11 format=3 uid="uid://clta811tt773x"] [ext_resource type="PackedScene" uid="uid://c8l60rnugru40" path="res://addons/godot-xr-tools/objects/pickable.tscn" id="1"] [ext_resource type="Material" path="res://assets/wahooney.itch.io/brown_grid_triplanar.tres" id="2"] @@ -6,6 +6,9 @@ [ext_resource type="Script" path="res://addons/godot-xr-tools/objects/highlight/highlight_visible.gd" id="3"] [ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="3_0q4lf"] +[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_bv5s3"] +bounce = 0.8 + [sub_resource type="SphereShape3D" id="2"] margin = 0.01 radius = 0.2 @@ -29,6 +32,8 @@ albedo_color = Color(1, 1, 0, 1) [node name="GrabBall" instance=ExtResource("1")] collision_mask = 720903 +mass = 10.0 +physics_material_override = SubResource("PhysicsMaterial_bv5s3") ranged_grab_method = 2 second_hand_grab = 2 diff --git a/scenes/pickable_demo/objects/hammer.tscn b/scenes/pickable_demo/objects/hammer.tscn index 0c28b5ca..dcc0f1f0 100644 --- a/scenes/pickable_demo/objects/hammer.tscn +++ b/scenes/pickable_demo/objects/hammer.tscn @@ -28,6 +28,7 @@ size = Vector3(0.1, 0.1, 0.2) [node name="Hammer" instance=ExtResource("1")] collision_mask = 7 +mass = 2.0 ranged_grab_method = 0 second_hand_grab = 2 diff --git a/scenes/pickable_demo/objects/picatinny_scope.tscn b/scenes/pickable_demo/objects/picatinny_scope.tscn index 68b9232c..c89d8d31 100644 --- a/scenes/pickable_demo/objects/picatinny_scope.tscn +++ b/scenes/pickable_demo/objects/picatinny_scope.tscn @@ -45,6 +45,7 @@ blend_shape_mode = 0 shadow_mesh = SubResource("ArrayMesh_mmp6s") [node name="PicatinnyScope" groups=["Picatinny"] instance=ExtResource("1_1xi8m")] +mass = 0.5 [node name="CollisionShape3D" parent="." index="0"] transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, 0.0028, 0.0208471, -0.0617341) diff --git a/scenes/pickable_demo/objects/teacup.tscn b/scenes/pickable_demo/objects/teacup.tscn index ce521ec4..38d5eea8 100644 --- a/scenes/pickable_demo/objects/teacup.tscn +++ b/scenes/pickable_demo/objects/teacup.tscn @@ -57,6 +57,7 @@ open_pose = ExtResource("7_m23hc") closed_pose = ExtResource("7_m23hc") [node name="Teacup" groups=["Teacup"] instance=ExtResource("1_q232w")] +mass = 0.2 second_hand_grab = 1 [node name="Teacup" type="MeshInstance3D" parent="." index="0"] diff --git a/scenes/pickable_demo/pickable_demo.gd b/scenes/pickable_demo/pickable_demo.gd new file mode 100644 index 00000000..b2b102be --- /dev/null +++ b/scenes/pickable_demo/pickable_demo.gd @@ -0,0 +1,16 @@ +extends DemoSceneBase + +@onready var left_hand : XRToolsHand = $XROrigin3D/LeftHand/XRToolsCollisionHand/LeftHand +@onready var left_ghost_hand : XRToolsHand = $XROrigin3D/LeftHand/GhostHand +@onready var right_hand : XRToolsHand = $XROrigin3D/RightHand/XRToolsCollisionHand/RightHand +@onready var right_ghost_hand : XRToolsHand = $XROrigin3D/RightHand/GhostHand + +func _process(_delta): + # Show our ghost hands when when our visible hands aren't where our hands are... + if left_hand and left_ghost_hand: + var offset = left_hand.global_position - left_ghost_hand.global_position + left_ghost_hand.visible = offset.length() > 0.01 + + if right_hand and right_ghost_hand: + var offset = right_hand.global_position - right_ghost_hand.global_position + right_ghost_hand.visible = offset.length() > 0.01 diff --git a/scenes/pickable_demo/pickable_demo.tscn b/scenes/pickable_demo/pickable_demo.tscn index 0482b559..980ac9b2 100644 --- a/scenes/pickable_demo/pickable_demo.tscn +++ b/scenes/pickable_demo/pickable_demo.tscn @@ -1,7 +1,7 @@ -[gd_scene load_steps=45 format=3 uid="uid://0c76wodjd7rm"] +[gd_scene load_steps=48 format=3 uid="uid://0c76wodjd7rm"] [ext_resource type="PackedScene" uid="uid://qbmx03iibuuu" path="res://addons/godot-xr-tools/staging/scene_base.tscn" id="1"] -[ext_resource type="Script" path="res://scenes/demo_scene_base.gd" id="2_kjksy"] +[ext_resource type="Script" path="res://scenes/pickable_demo/pickable_demo.gd" id="2_bs8b6"] [ext_resource type="PackedScene" uid="uid://yrg5yt0yvc1q" path="res://addons/godot-xr-tools/hands/scenes/collision/collision_hand.tscn" id="3_m7tr4"] [ext_resource type="PackedScene" uid="uid://bjcxf427un2wp" path="res://addons/godot-xr-tools/player/poke/poke.tscn" id="4_iyttx"] [ext_resource type="PackedScene" uid="uid://3a6wjr3a13vd" path="res://assets/meshes/teleport/teleport.tscn" id="5"] @@ -15,6 +15,7 @@ [ext_resource type="PackedScene" uid="uid://raeeicvvindd" path="res://addons/godot-xr-tools/hands/scenes/highpoly/right_hand.tscn" id="9_v8epv"] [ext_resource type="PackedScene" uid="uid://b6bk2pj8vbj28" path="res://addons/godot-xr-tools/functions/movement_turn.tscn" id="10"] [ext_resource type="PackedScene" uid="uid://1mb16xioom74" path="res://scenes/pickable_demo/objects/belt_snap_zone.tscn" id="10_5odnk"] +[ext_resource type="Material" uid="uid://c5jkrtp4eipf4" path="res://scenes/pickable_demo/materials/ghost_hands.tres" id="10_gr6u1"] [ext_resource type="PackedScene" uid="uid://cf024hg5alcif" path="res://scenes/pickable_demo/objects/snap_toy_red.tscn" id="11"] [ext_resource type="PackedScene" uid="uid://deyk5frilshws" path="res://assets/meshes/control_pad/control_pad_location_right.tscn" id="11_dk12d"] [ext_resource type="PackedScene" uid="uid://cboxrvj4xdi6f" path="res://scenes/pickable_demo/objects/snap_toy_yellow.tscn" id="12"] @@ -26,86 +27,108 @@ [ext_resource type="PackedScene" uid="uid://ct3p5sgwvkmva" path="res://assets/meshes/control_pad/control_pad.tscn" id="14_xqgdl"] [ext_resource type="PackedScene" uid="uid://bwcpq6cuejbiy" path="res://assets/meshes/table/table.tscn" id="15"] [ext_resource type="PackedScene" uid="uid://b3mykwawmnxpi" path="res://scenes/pickable_demo/objects/teacup_stand.tscn" id="15_bq355"] +[ext_resource type="PackedScene" uid="uid://l2n30mpbkdyw" path="res://addons/godot-xr-tools/hands/scenes/lowpoly/right_hand_low.tscn" id="15_v4ej7"] [ext_resource type="PackedScene" uid="uid://c6rmke57xw5lg" path="res://scenes/pickable_demo/objects/snap_tray.tscn" id="16"] [ext_resource type="PackedScene" uid="uid://chww0na0ryl1m" path="res://scenes/pickable_demo/objects/teacup.tscn" id="16_v5unt"] [ext_resource type="PackedScene" uid="uid://de0guxhrn5ouk" path="res://scenes/pickable_demo/objects/hammer.tscn" id="17"] [ext_resource type="PackedScene" uid="uid://bxk2dud5pq1uf" path="res://scenes/pickable_demo/objects/knife.tscn" id="19_6grml"] [ext_resource type="Script" path="res://addons/godot-xr-tools/objects/return_to_snap_zone.gd" id="19_iqmkd"] [ext_resource type="PackedScene" uid="uid://bmjemjgtnpkpo" path="res://assets/3dmodelscc0/models/scenes/sniper_rifle.tscn" id="25_xgu4l"] -[ext_resource type="PackedScene" uid="uid://dfu08adatg63i" path="res://scenes/pickable_demo/objects/picatinny_scope.tscn" id="26_x40vw"] +[ext_resource type="PackedScene" uid="uid://deuxld12hxsq0" path="res://scenes/pickable_demo/objects/picatinny_scope.tscn" id="26_x40vw"] -[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_lk0rx"] +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_leov0"] animation = &"Grip" -[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_byatp"] +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_tdgjj"] animation = &"Grip" -[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_lh7tw"] +[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_ant8f"] filter_enabled = true filters = ["Armature/Skeleton3D:Little_Distal_L", "Armature/Skeleton3D:Little_Intermediate_L", "Armature/Skeleton3D:Little_Metacarpal_L", "Armature/Skeleton3D:Little_Proximal_L", "Armature/Skeleton3D:Middle_Distal_L", "Armature/Skeleton3D:Middle_Intermediate_L", "Armature/Skeleton3D:Middle_Metacarpal_L", "Armature/Skeleton3D:Middle_Proximal_L", "Armature/Skeleton3D:Ring_Distal_L", "Armature/Skeleton3D:Ring_Intermediate_L", "Armature/Skeleton3D:Ring_Metacarpal_L", "Armature/Skeleton3D:Ring_Proximal_L", "Armature/Skeleton3D:Thumb_Distal_L", "Armature/Skeleton3D:Thumb_Metacarpal_L", "Armature/Skeleton3D:Thumb_Proximal_L", "Armature/Skeleton:Little_Distal_L", "Armature/Skeleton:Little_Intermediate_L", "Armature/Skeleton:Little_Proximal_L", "Armature/Skeleton:Middle_Distal_L", "Armature/Skeleton:Middle_Intermediate_L", "Armature/Skeleton:Middle_Proximal_L", "Armature/Skeleton:Ring_Distal_L", "Armature/Skeleton:Ring_Intermediate_L", "Armature/Skeleton:Ring_Proximal_L", "Armature/Skeleton:Thumb_Distal_L", "Armature/Skeleton:Thumb_Proximal_L"] -[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_0hde5"] +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_baddp"] animation = &"Grip 5" -[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_1myux"] +[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_41aoc"] filter_enabled = true filters = ["Armature/Skeleton3D:Index_Distal_L", "Armature/Skeleton3D:Index_Intermediate_L", "Armature/Skeleton3D:Index_Metacarpal_L", "Armature/Skeleton3D:Index_Proximal_L", "Armature/Skeleton:Index_Distal_L", "Armature/Skeleton:Index_Intermediate_L", "Armature/Skeleton:Index_Proximal_L"] -[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_add5h"] +[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_8kmfh"] graph_offset = Vector2(-536, 11) -nodes/ClosedHand1/node = SubResource("AnimationNodeAnimation_lk0rx") +nodes/ClosedHand1/node = SubResource("AnimationNodeAnimation_leov0") nodes/ClosedHand1/position = Vector2(-600, 300) -nodes/ClosedHand2/node = SubResource("AnimationNodeAnimation_byatp") +nodes/ClosedHand2/node = SubResource("AnimationNodeAnimation_tdgjj") nodes/ClosedHand2/position = Vector2(-360, 300) -nodes/Grip/node = SubResource("AnimationNodeBlend2_lh7tw") +nodes/Grip/node = SubResource("AnimationNodeBlend2_ant8f") nodes/Grip/position = Vector2(0, 20) -nodes/OpenHand/node = SubResource("AnimationNodeAnimation_0hde5") +nodes/OpenHand/node = SubResource("AnimationNodeAnimation_baddp") nodes/OpenHand/position = Vector2(-600, 100) -nodes/Trigger/node = SubResource("AnimationNodeBlend2_1myux") +nodes/Trigger/node = SubResource("AnimationNodeBlend2_41aoc") nodes/Trigger/position = Vector2(-360, 20) node_connections = [&"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1", &"output", 0, &"Grip"] -[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_0loxr"] +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_8ri27"] animation = &"Grip" -[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_brc6o"] +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_oe64k"] animation = &"Grip" -[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_kiqrg"] +[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_7sh5g"] filter_enabled = true filters = ["Armature/Skeleton3D:Little_Distal_R", "Armature/Skeleton3D:Little_Intermediate_R", "Armature/Skeleton3D:Little_Metacarpal_R", "Armature/Skeleton3D:Little_Proximal_R", "Armature/Skeleton3D:Middle_Distal_R", "Armature/Skeleton3D:Middle_Intermediate_R", "Armature/Skeleton3D:Middle_Metacarpal_R", "Armature/Skeleton3D:Middle_Proximal_R", "Armature/Skeleton3D:Ring_Distal_R", "Armature/Skeleton3D:Ring_Intermediate_R", "Armature/Skeleton3D:Ring_Metacarpal_R", "Armature/Skeleton3D:Ring_Proximal_R", "Armature/Skeleton3D:Thumb_Distal_R", "Armature/Skeleton3D:Thumb_Metacarpal_R", "Armature/Skeleton3D:Thumb_Proximal_R", "Armature/Skeleton:Little_Distal_R", "Armature/Skeleton:Little_Intermediate_R", "Armature/Skeleton:Little_Proximal_R", "Armature/Skeleton:Middle_Distal_R", "Armature/Skeleton:Middle_Intermediate_R", "Armature/Skeleton:Middle_Proximal_R", "Armature/Skeleton:Ring_Distal_R", "Armature/Skeleton:Ring_Intermediate_R", "Armature/Skeleton:Ring_Proximal_R", "Armature/Skeleton:Thumb_Distal_R", "Armature/Skeleton:Thumb_Proximal_R"] -[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_a6vop"] +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_re3ic"] animation = &"Grip 5" -[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_utpbw"] +[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_epdw0"] filter_enabled = true filters = ["Armature/Skeleton3D:Index_Distal_R", "Armature/Skeleton3D:Index_Intermediate_R", "Armature/Skeleton3D:Index_Metacarpal_R", "Armature/Skeleton3D:Index_Proximal_R", "Armature/Skeleton:Index_Distal_R", "Armature/Skeleton:Index_Intermediate_R", "Armature/Skeleton:Index_Proximal_R"] -[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_utbhi"] +[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_x1lgc"] graph_offset = Vector2(-552.664, 107.301) -nodes/ClosedHand1/node = SubResource("AnimationNodeAnimation_0loxr") +nodes/ClosedHand1/node = SubResource("AnimationNodeAnimation_8ri27") nodes/ClosedHand1/position = Vector2(-600, 300) -nodes/ClosedHand2/node = SubResource("AnimationNodeAnimation_brc6o") +nodes/ClosedHand2/node = SubResource("AnimationNodeAnimation_oe64k") nodes/ClosedHand2/position = Vector2(-360, 300) -nodes/Grip/node = SubResource("AnimationNodeBlend2_kiqrg") +nodes/Grip/node = SubResource("AnimationNodeBlend2_7sh5g") nodes/Grip/position = Vector2(0, 40) -nodes/OpenHand/node = SubResource("AnimationNodeAnimation_a6vop") +nodes/OpenHand/node = SubResource("AnimationNodeAnimation_re3ic") nodes/OpenHand/position = Vector2(-600, 100) -nodes/Trigger/node = SubResource("AnimationNodeBlend2_utpbw") +nodes/Trigger/node = SubResource("AnimationNodeBlend2_epdw0") nodes/Trigger/position = Vector2(-360, 40) node_connections = [&"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1", &"output", 0, &"Grip"] [node name="PickableDemo" instance=ExtResource("1")] -script = ExtResource("2_kjksy") +script = ExtResource("2_bs8b6") [node name="XRToolsCollisionHand" parent="XROrigin3D/LeftHand" index="0" node_paths=PackedStringArray("hand_skeleton") instance=ExtResource("3_m7tr4")] hand_skeleton = NodePath("LeftHand/Hand_Nails_low_L/Armature/Skeleton3D") [node name="LeftHand" parent="XROrigin3D/LeftHand/XRToolsCollisionHand" index="0" instance=ExtResource("7_ywaf6")] +[node name="Skeleton3D" parent="XROrigin3D/LeftHand/XRToolsCollisionHand/LeftHand/Hand_Nails_low_L/Armature" index="0"] +bones/1/rotation = Quaternion(0.323537, -2.56577e-05, -0.0272204, 0.945824) +bones/2/rotation = Quaternion(-0.0904441, -0.0415175, -0.166293, 0.981042) +bones/3/rotation = Quaternion(-0.0466199, 0.020971, 0.0103276, 0.998639) +bones/5/rotation = Quaternion(-0.00128455, -0.0116081, -0.0168259, 0.99979) +bones/6/rotation = Quaternion(0.102925, -0.00993208, -0.00794417, 0.994608) +bones/7/rotation = Quaternion(-0.012859, -0.0236108, -0.323258, 0.945929) +bones/8/rotation = Quaternion(0.0120575, -0.00929194, -0.247472, 0.968775) +bones/10/rotation = Quaternion(-0.0357539, -0.000400032, 0.00636764, 0.99934) +bones/11/rotation = Quaternion(-0.00264964, -0.00114471, -0.125992, 0.992027) +bones/12/rotation = Quaternion(0.0394225, 0.00193393, -0.228074, 0.972843) +bones/13/rotation = Quaternion(-0.0123395, -0.00881294, -0.280669, 0.959685) +bones/15/rotation = Quaternion(-0.0702656, 0.0101908, -0.0243307, 0.99718) +bones/16/rotation = Quaternion(-0.0320634, -0.00223624, -0.0686366, 0.997124) +bones/17/rotation = Quaternion(0.0253452, 0.00812462, -0.249005, 0.968136) +bones/18/rotation = Quaternion(0.00252232, 0.00788073, -0.243204, 0.96994) +bones/20/rotation = Quaternion(-0.0917369, 0.0203027, -0.010183, 0.995524) +bones/21/rotation = Quaternion(-0.0625182, -0.00022572, -0.115393, 0.991351) +bones/22/rotation = Quaternion(0.0585786, 0.0216483, -0.269905, 0.96086) +bones/23/rotation = Quaternion(0.00687177, -0.00357275, -0.211953, 0.977249) + [node name="BoneAttachment3D" type="BoneAttachment3D" parent="XROrigin3D/LeftHand/XRToolsCollisionHand/LeftHand/Hand_Nails_low_L/Armature/Skeleton3D" index="1"] -transform = Transform3D(0.54083, 0.840812, -0.0231736, -0.0826267, 0.0805244, 0.993322, 0.837063, -0.535304, 0.113024, 0.0399019, 0.0402829, -0.150096) +transform = Transform3D(0.54083, 0.840813, -0.0231736, -0.0826267, 0.0805243, 0.993322, 0.837064, -0.535303, 0.113023, 0.039902, 0.0402828, -0.150096) bone_name = "Index_Tip_L" bone_idx = 9 @@ -116,7 +139,7 @@ push_bodies = false [node name="AnimationTree" parent="XROrigin3D/LeftHand/XRToolsCollisionHand/LeftHand" index="1"] root_node = NodePath("../Hand_Nails_low_L") -tree_root = SubResource("AnimationNodeBlendTree_add5h") +tree_root = SubResource("AnimationNodeBlendTree_8kmfh") [node name="MovementDirect" parent="XROrigin3D/LeftHand/XRToolsCollisionHand" index="1" instance=ExtResource("7")] strafe = true @@ -127,13 +150,38 @@ ranged_angle = 10.0 [node name="ControlPadLocationLeft" parent="XROrigin3D/LeftHand/XRToolsCollisionHand" index="3" instance=ExtResource("7_fdgf8")] +[node name="GhostHand" parent="XROrigin3D/LeftHand" index="1" instance=ExtResource("7_ywaf6")] +visible = false +hand_material_override = ExtResource("10_gr6u1") + [node name="XRToolsCollisionHand" parent="XROrigin3D/RightHand" index="0" node_paths=PackedStringArray("hand_skeleton") instance=ExtResource("3_m7tr4")] hand_skeleton = NodePath("RightHand/Hand_Nails_R/Armature/Skeleton3D") [node name="RightHand" parent="XROrigin3D/RightHand/XRToolsCollisionHand" index="0" instance=ExtResource("9_v8epv")] +[node name="Skeleton3D" parent="XROrigin3D/RightHand/XRToolsCollisionHand/RightHand/Hand_Nails_R/Armature" index="0"] +bones/1/rotation = Quaternion(0.323537, 2.56577e-05, 0.0272204, 0.945824) +bones/2/rotation = Quaternion(-0.0904441, 0.0415175, 0.166293, 0.981042) +bones/3/rotation = Quaternion(-0.0466199, -0.020971, -0.0103276, 0.998639) +bones/5/rotation = Quaternion(-0.00128455, 0.0116081, 0.0168259, 0.99979) +bones/6/rotation = Quaternion(0.102925, 0.00993208, 0.00794419, 0.994608) +bones/7/rotation = Quaternion(-0.012859, 0.0236108, 0.323258, 0.945929) +bones/8/rotation = Quaternion(0.0120575, 0.00929193, 0.247472, 0.968775) +bones/10/rotation = Quaternion(-0.0357539, 0.000400032, -0.00636763, 0.99934) +bones/11/rotation = Quaternion(-0.00264964, 0.00114471, 0.125992, 0.992027) +bones/12/rotation = Quaternion(0.0394225, -0.00193393, 0.228074, 0.972843) +bones/13/rotation = Quaternion(-0.0123395, 0.00881294, 0.280669, 0.959685) +bones/15/rotation = Quaternion(-0.0702656, -0.0101908, 0.0243307, 0.99718) +bones/16/rotation = Quaternion(-0.0320634, 0.00223624, 0.0686366, 0.997124) +bones/17/rotation = Quaternion(0.0253452, -0.00812462, 0.249005, 0.968136) +bones/18/rotation = Quaternion(0.00252233, -0.00788073, 0.243204, 0.96994) +bones/20/rotation = Quaternion(-0.0917369, -0.0203027, 0.010183, 0.995524) +bones/21/rotation = Quaternion(-0.0625182, 0.000225721, 0.115393, 0.991351) +bones/22/rotation = Quaternion(0.0585786, -0.0216483, 0.269905, 0.96086) +bones/23/rotation = Quaternion(0.00687177, 0.00357275, 0.211953, 0.977249) + [node name="BoneAttachment3D" type="BoneAttachment3D" parent="XROrigin3D/RightHand/XRToolsCollisionHand/RightHand/Hand_Nails_R/Armature/Skeleton3D" index="1"] -transform = Transform3D(0.54083, -0.840812, 0.0231736, 0.0826267, 0.0805244, 0.993322, -0.837063, -0.535304, 0.113024, -0.0399019, 0.0402829, -0.150096) +transform = Transform3D(0.540829, -0.840813, 0.0231736, 0.0826268, 0.0805242, 0.993322, -0.837064, -0.535303, 0.113024, -0.039902, 0.0402828, -0.150096) bone_name = "Index_Tip_R" bone_idx = 9 @@ -144,7 +192,7 @@ push_bodies = false [node name="AnimationTree" parent="XROrigin3D/RightHand/XRToolsCollisionHand/RightHand" index="1"] root_node = NodePath("../Hand_Nails_R") -tree_root = SubResource("AnimationNodeBlendTree_utbhi") +tree_root = SubResource("AnimationNodeBlendTree_x1lgc") [node name="MovementDirect" parent="XROrigin3D/RightHand/XRToolsCollisionHand" index="1" instance=ExtResource("7")] @@ -160,6 +208,10 @@ laser_length = 1 [node name="ControlPadLocationRight" parent="XROrigin3D/RightHand/XRToolsCollisionHand" index="5" instance=ExtResource("11_dk12d")] +[node name="GhostHand" parent="XROrigin3D/RightHand" index="1" instance=ExtResource("15_v4ej7")] +visible = false +hand_material_override = ExtResource("10_gr6u1") + [node name="PlayerBody" parent="XROrigin3D" index="3" instance=ExtResource("9")] [node name="BeltSnapZone01" parent="XROrigin3D/PlayerBody" index="0" instance=ExtResource("10_5odnk")]