From 882fc56b2a232db1440742cb1c4125ffa45cc925 Mon Sep 17 00:00:00 2001 From: Malcolm Nixon Date: Tue, 14 Jun 2022 20:22:47 -0400 Subject: [PATCH] Added advanced player height control Modified climbing to collapse player to a sphere to allow mounting climbed objects Added crouch movement provider Added advanced player height control Modified climbing to collapse player to a sphere to allow mounting climbed objects Added crouch movement provider Modified height override to use 'self' as per recommendation. --- addons/godot-xr-tools/VERSIONS.md | 5 ++ addons/godot-xr-tools/assets/PlayerBody.gd | 54 +++++++++++-- .../functions/Function_Climb_movement.gd | 2 + .../functions/Function_Crouch_movement.gd | 81 +++++++++++++++++++ .../functions/Function_Crouch_movement.tscn | 6 ++ 5 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 addons/godot-xr-tools/functions/Function_Crouch_movement.gd create mode 100644 addons/godot-xr-tools/functions/Function_Crouch_movement.tscn diff --git a/addons/godot-xr-tools/VERSIONS.md b/addons/godot-xr-tools/VERSIONS.md index 1084cd1c..fe7018d4 100644 --- a/addons/godot-xr-tools/VERSIONS.md +++ b/addons/godot-xr-tools/VERSIONS.md @@ -1,3 +1,8 @@ +# 2.5.0 +- Added advanced player height control +- Modified climbing to collapse player to a sphere to allow mounting climbed objects +- Added crouch movement provider + # 2.4.1 - Fixed grab distance - Fixed snap-zone instance drop and free issue diff --git a/addons/godot-xr-tools/assets/PlayerBody.gd b/addons/godot-xr-tools/assets/PlayerBody.gd index 75ca837b..58ec97fd 100644 --- a/addons/godot-xr-tools/assets/PlayerBody.gd +++ b/addons/godot-xr-tools/assets/PlayerBody.gd @@ -38,6 +38,12 @@ export var player_radius := 0.4 setget set_player_radius ## Player head height (distance between between camera and top of head) export var player_head_height := 0.1 +## Minimum player height +export var player_height_min := 1.0 + +## Maximum player height +export var player_height_max := 2.2 + ## Eyes forward offset from center of body in player_radius units export (float, 0.0, 1.0) var eye_forward_offset := 0.66 @@ -78,12 +84,22 @@ var ground_physics: GroundPhysicsSettings = null ## Ground control velocity - modified by MovementProvider nodes var ground_control_velocity := Vector2.ZERO +## Player height offset (for height calibration) +var player_height_offset := 0.0 + + # Movement providers var _movement_providers := Array() # Jump cool-down counter var _jump_cooldown := 0 +## Player height overrides +var _player_height_overrides := { } + +# Player height override (enabled when non-negative) +var _player_height_override := -1.0 + ## ARVROrigin node onready var origin_node := ARVRHelpers.get_arvr_origin(self) @@ -248,12 +264,32 @@ func request_jump(var skip_jump_velocity := false): func move_and_slide(var velocity: Vector3) -> Vector3: return kinematic_node.move_and_slide(velocity, Vector3.UP, false, 4, 0.785398, push_rigid_bodies) +# Set or clear a named height override +func override_player_height(key, value: float = -1.0): + # Clear or set the override + if value < 0.0: + _player_height_overrides.erase(key) + else: + _player_height_overrides[key] = value + + # Set or clear the override value + var override = _player_height_overrides.values().min() + _player_height_override = override if override != null else -1.0 + # This method updates the body to match the player position func _update_body_under_camera(): - # Calculate the player height based on the origin and camera position - var player_height := camera_node.transform.origin.y + player_head_height - if player_height < player_radius: - player_height = player_radius + # Calculate the player height based on the camera position in the origin and the calibration + var player_height := clamp( + camera_node.transform.origin.y + player_head_height + player_height_offset, + player_height_min, + player_height_max) + + # Allow forced overriding of height + if _player_height_override >= 0.0: + player_height = _player_height_override + + # Ensure player height makes mathematical sense + player_height = max(player_height, player_radius * 2.0) # Adjust the collision shape to match the player geometry _collision_node.shape.radius = player_radius @@ -264,7 +300,7 @@ func _update_body_under_camera(): var curr_transform := kinematic_node.global_transform var camera_transform := camera_node.global_transform curr_transform.origin = camera_transform.origin - curr_transform.origin.y = origin_node.global_transform.origin.y + curr_transform.origin.y += player_head_height - player_height # The camera/eyes are towards the front of the body, so move the body back slightly var forward_dir := -camera_transform.basis.z * HORIZONTAL @@ -374,6 +410,14 @@ func _get_configuration_warning(): if player_radius <= 0: return "Player radius must be configured" + # Verify the player height minimum is valid + if player_height_min < player_radius * 2.0: + return "Player height minimum smaller than 2x radius" + + # Verify the player height maximum is valid + if player_height_max < player_height_min: + return "Player height maximum cannot be smaller than minimum" + # Verify eye-forward does not allow near-clip-plane look through var eyes_to_collider = (1.0 - eye_forward_offset) * player_radius if eyes_to_collider < test_camera_node.near: diff --git a/addons/godot-xr-tools/functions/Function_Climb_movement.gd b/addons/godot-xr-tools/functions/Function_Climb_movement.gd index 7cf6e9cc..e3367ee5 100644 --- a/addons/godot-xr-tools/functions/Function_Climb_movement.gd +++ b/addons/godot-xr-tools/functions/Function_Climb_movement.gd @@ -122,11 +122,13 @@ func _set_climbing(active: bool, player_body: PlayerBody) -> void: if is_active: _distances.clear() _deltas.clear() + player_body.override_player_height(self, 0.0) emit_signal("player_climb_start") else: var velocity := _average_velocity() var dir_forward = -(player_body.camera_node.global_transform.basis.z * HORIZONTAL).normalized() player_body.velocity = (velocity * fling_multiplier) + (dir_forward * forward_push) + player_body.override_player_height(self) emit_signal("player_climb_end") diff --git a/addons/godot-xr-tools/functions/Function_Crouch_movement.gd b/addons/godot-xr-tools/functions/Function_Crouch_movement.gd new file mode 100644 index 00000000..5b1630c6 --- /dev/null +++ b/addons/godot-xr-tools/functions/Function_Crouch_movement.gd @@ -0,0 +1,81 @@ +tool +class_name Function_CrouchMovement +extends MovementProvider + +## +## Movement Provider for Crouching +## +## @desc: +## This script works with the PlayerBody attached to the players ARVROrigin. +## +## When the player presses the selected button, the height is overridden +## to the crouch height +## + + +# enum our buttons, should find a way to put this more central +enum Buttons { + VR_BUTTON_BY = 1, + VR_GRIP = 2, + VR_BUTTON_3 = 3, + VR_BUTTON_4 = 4, + VR_BUTTON_5 = 5, + VR_BUTTON_6 = 6, + VR_BUTTON_AX = 7, + VR_BUTTON_8 = 8, + VR_BUTTON_9 = 9, + VR_BUTTON_10 = 10, + VR_BUTTON_11 = 11, + VR_BUTTON_12 = 12, + VR_BUTTON_13 = 13, + VR_PAD = 14, + VR_TRIGGER = 15 +} + + +## Movement provider order +export var order := 10 + +## Crouch height +export var crouch_height := 1.0 + +## Crouch button +export (Buttons) var crouch_button: int = Buttons.VR_PAD + + +## Crouching flag +var _crouching := false + + +# Controller node +onready var _controller : ARVRController = get_parent() + + +# Perform jump movement +func physics_movement(delta: float, player_body: PlayerBody, _disabled: bool): + # Skip if the controller isn't active + if !_controller.get_is_active(): + return + + # Check for crouching change + var crouching := _controller.is_button_pressed(crouch_button) != 0 + if crouching == _crouching: + return + + # Update crouching state + _crouching = crouching + if crouching: + player_body.override_player_height(self, crouch_height) + else: + player_body.override_player_height(self) + + +# This method verifies the MovementProvider has a valid configuration. +func _get_configuration_warning(): + # Check the controller node + var test_controller = get_parent() + if !test_controller or !test_controller is ARVRController: + return "Unable to find ARVR Controller node" + + # Call base class + return ._get_configuration_warning() diff --git a/addons/godot-xr-tools/functions/Function_Crouch_movement.tscn b/addons/godot-xr-tools/functions/Function_Crouch_movement.tscn new file mode 100644 index 00000000..781876c6 --- /dev/null +++ b/addons/godot-xr-tools/functions/Function_Crouch_movement.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/godot-xr-tools/functions/Function_Crouch_movement.gd" type="Script" id=1] + +[node name="Function_Crouch_movement" type="Node" groups=["movement_providers"]] +script = ExtResource( 1 )