Skip to content

Commit

Permalink
Modified XRToolsPlayerBody to use the ARVROrigin basis.y for its up v…
Browse files Browse the repository at this point in the history
…ector. Added demo scene with ground-following movement provider to test the new up-vector logic.

Added player orientation provider support to the XRToolsPlayerBody. Added ground and area orientation providers. Added path, point, and uniform orient areas to control the player orientation in different areas. Enhanced origin gravity demo to use orient areas to better handle player movement around the sphere and pill shapes.

Removed experimental world-grab provider not intended for this PR

Fixed climbing to work in the players orientation. Fixed flight to work in the players orientation. Fixed glide to work in the players orientation. Added sphere world demo.

Removed orientation providers - orientation now comes from gravity as detected by the player body. Modified gravity demos to use standard Area nodes with space_override settings. Added movement_wall_walk to walk on walls of the specified physics layer.

Further cleanup of orientation providers and unnecessary changes.
  • Loading branch information
Malcolmnixon committed Dec 24, 2022
1 parent 05f7d20 commit 49a49ea
Show file tree
Hide file tree
Showing 26 changed files with 849 additions and 167 deletions.
11 changes: 7 additions & 4 deletions addons/godot-xr-tools/functions/movement_climb.gd
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ signal player_climb_start
signal player_climb_end


## Horizontal vector used to calculate the horizontal component of vectors
const HORIZONTAL := Vector3(1.0, 0.0, 1.0)

## Distance at which grabs snap
const SNAP_DISTANCE : float = 1.0

Expand Down Expand Up @@ -149,9 +146,15 @@ func _set_climbing(active: bool, player_body: XRToolsPlayerBody) -> void:
player_body.override_player_height(self, 0.0)
emit_signal("player_climb_start")
else:
# Calculate the forward direction (based on camera-forward)
var dir_forward = -player_body.up_plane.project(
player_body.camera_node.global_transform.basis.z).normalized()

# Set player velocity based on averaged velocity, fling multiplier,
# and a forward push
var velocity := _averager.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")

Expand Down
86 changes: 38 additions & 48 deletions addons/godot-xr-tools/functions/movement_flight.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,30 @@ class_name XRToolsMovementFlight
extends XRToolsMovementProvider


## XR Tools Movement Provider for Flying
##
## Movement Provider for Flying
## This script provides flying movement for the player. The control parameters
## are intended to support a wide variety of flight mechanics.
##
## @desc:
## This script provides flying movement for the player. The control parameters
## are intended to support a wide variety of flight mechanics.
## Pitch and Bearing input devices are selected which produce a "forwards"
## reference frame. The player controls (forwards/backwards and
## left/right) are applied in relation to this reference frame.
##
## Pitch and Bearing input devices are selected which produce a "forwards"
## reference frame. The player controls (forwards/backwards and
## left/right) are applied in relation to this reference frame.
## The Speed Scale and Traction parameters allow primitive flight where
## the player is in direct control of their speed (in the reference frame).
## This produces an effect described as the "Mary Poppins Flying Umbrella".
##
## The Speed Scale and Traction parameters allow primitive flight where
## the player is in direct control of their speed (in the reference frame).
## This produces an effect described as the "Mary Poppins Flying Umbrella".
## The Acceleration, Drag, and Guidance parameters allow for slightly more
## realisitic flying where the player can accelerate in their reference
## frame. The drag is applied against the global reference and can be used
## to construct a terminal velocity.
##
## The Acceleration, Drag, and Guidance parameters allow for slightly more
## realisitic flying where the player can accelerate in their reference
## frame. The drag is applied against the global reference and can be used
## to construct a terminal velocity.
##
## The Guidance property attempts to lerp the players velocity into flight
## forwards direction as if the player had guide-fins or wings.
##
## The Exclusive property specifies whether flight is exclusive (no further
## physics effects after flying) or whether additional effects such as
## the default player gravity are applied.
## The Guidance property attempts to lerp the players velocity into flight
## forwards direction as if the player had guide-fins or wings.
##
## The Exclusive property specifies whether flight is exclusive (no further
## physics effects after flying) or whether additional effects such as
## the default player gravity are applied.


## Signal emitted when flight starts
Expand All @@ -39,33 +36,26 @@ signal flight_started()
signal flight_finished()


# Enumeration of controller to use for flight
## Enumeration of controller to use for flight
enum FlightController {
LEFT, # Use left controller
RIGHT, # Use right controler
LEFT, ## Use left controller
RIGHT, ## Use right controler
}

# Enumeration of pitch control input
## Enumeration of pitch control input
enum FlightPitch {
HEAD, # Head controls pitch
CONTROLLER, # Controller controls pitch
HEAD, ## Head controls pitch
CONTROLLER, ## Controller controls pitch
}

# Enumeration of bearing control input
## Enumeration of bearing control input
enum FlightBearing {
HEAD, # Head controls bearing
CONTROLLER, # Controller controls bearing
BODY, # Body controls bearing
HEAD, ## Head controls bearing
CONTROLLER, ## Controller controls bearing
BODY, ## Body controls bearing
}


# Vector3 for getting vertical component
const VERTICAL := Vector3(0.0, 1.0, 0.0)

# Vector3 for getting horizontal component
const HORIZONTAL := Vector3(1.0, 0.0, 1.0)


## Movement provider order
export var order : int = 30

Expand Down Expand Up @@ -100,10 +90,10 @@ export var guidance : float = 0.0
export var exclusive : bool = true


# Flight button state
## Flight button state
var _flight_button : bool = false

# Flight controller
## Flight controller
var _controller : ARVRController


Expand All @@ -126,7 +116,7 @@ func _ready():
_controller = _right_controller


# Process physics movement for
# Process physics movement for flight
func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bool):
# Disable flying if requested, or if no controller
if disabled or !enabled or !_controller.get_is_active():
Expand All @@ -147,29 +137,29 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo
var pitch_vector: Vector3
if pitch == FlightPitch.HEAD:
# Use the vertical part of the 'head' forwards vector
pitch_vector = -_camera.global_transform.basis.z.y * VERTICAL
pitch_vector = -_camera.transform.basis.z.y * player_body.up_vector
else:
# Use the vertical part of the 'controller' forwards vector
pitch_vector = -_controller.global_transform.basis.z.y * VERTICAL
pitch_vector = -_controller.transform.basis.z.y * player_body.up_vector

# Select the bearing vector
var bearing_vector: Vector3
if bearing == FlightBearing.HEAD:
# Use the horizontal part of the 'head' forwards vector
bearing_vector = -_camera.global_transform.basis.z * HORIZONTAL
bearing_vector = -player_body.up_plane.project(_camera.global_transform.basis.z)
elif bearing == FlightBearing.CONTROLLER:
# Use the horizontal part of the 'controller' forwards vector
bearing_vector = -_controller.global_transform.basis.z * HORIZONTAL
bearing_vector = -player_body.up_plane.project(_controller.global_transform.basis.z)
else:
# Use the horizontal part of the 'body' forwards vector
var left := _left_controller.global_transform.origin
var right := _right_controller.global_transform.origin
var left_to_right := (right - left) * HORIZONTAL
bearing_vector = left_to_right.rotated(Vector3.UP, PI/2)
var left_to_right := right - left
bearing_vector = player_body.up_plane.project(left_to_right.rotated(player_body.up_vector, PI/2))

# Construct the flight bearing
var forwards := (bearing_vector.normalized() + pitch_vector).normalized()
var side := forwards.cross(Vector3.UP)
var side := forwards.cross(player_body.up_vector)

# Construct the target velocity
var joy_forwards := _controller.get_joystick_axis(XRTools.Axis.VR_PRIMARY_Y_AXIS)
Expand Down
54 changes: 18 additions & 36 deletions addons/godot-xr-tools/functions/movement_glide.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,20 @@ class_name XRToolsMovementGlide
extends XRToolsMovementProvider


## XR Tools Movement Provider for Gliding
##
## Movement Provider for Gliding
## This script provides glide mechanics for the player. This script works
## with the [XRToolsPlayerBody] attached to the players [ARVROrigin].
##
## @desc:
## This script provides glide mechanics for the player. This script works
## with the PlayerBody attached to the players ARVROrigin.
## The player enables flying by moving the controllers apart further than
## 'glide_detect_distance'.
##
## The player enables flying by moving the controllers apart further than
## 'glide_detect_distance'.
##
## When gliding, the players fall speed will slew to 'glide_fall_speed' and
## the velocity will slew to 'glide_forward_speed' in the direction the
## player is facing.
##
## Gliding is an exclusive motion operation, and so gliding should be ordered
## after any Direct movement providers responsible for turning.
## When gliding, the players fall speed will slew to 'glide_fall_speed' and
## the velocity will slew to 'glide_forward_speed' in the direction the
## player is facing.
##
## Gliding is an exclusive motion operation, and so gliding should be ordered
## after any Direct movement providers responsible for turning.


## Signal invoked when the player starts gliding
Expand All @@ -29,10 +26,6 @@ signal player_glide_start
signal player_glide_end


# Horizontal vector (multiply by this to get only the horizontal components
const HORIZONTAL := Vector3(1.0, 0.0, 1.0)


## Movement provider order
export var order : int = 35

Expand Down Expand Up @@ -80,19 +73,19 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo
return

# If on the ground, or not falling, then not gliding
if player_body.on_ground || player_body.velocity.y >= glide_min_fall_speed:
var vertical_velocity := player_body.velocity.dot(player_body.up_vector)
if player_body.on_ground || vertical_velocity >= glide_min_fall_speed:
_set_gliding(false)
return

# Get the controller left and right global horizontal positions
var left_position := _left_controller.global_transform.origin
var right_position := _right_controller.global_transform.origin
var left_to_right_vector := right_position - left_position
var left_to_right := (left_to_right_vector) * HORIZONTAL
var left_to_right := right_position - left_position

if turn_with_roll:
var angle = -left_to_right_vector.y
_rotate_player(player_body, roll_turn_speed * delta * angle)
var angle = -left_to_right.dot(player_body.up_vector)
player_body.rotate_player(roll_turn_speed * delta * angle)

# Set gliding based on hand separation
var separation := left_to_right.length() / ARVRServer.world_scale
Expand All @@ -103,32 +96,21 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo
return

# Lerp the vertical velocity to glide_fall_speed
var vertical_velocity := player_body.velocity.y
vertical_velocity = lerp(vertical_velocity, glide_fall_speed, vertical_slew_rate * delta)

# Lerp the horizontal velocity towards forward_speed
var horizontal_velocity := player_body.velocity * HORIZONTAL
var dir_forward := left_to_right.rotated(Vector3.UP, PI/2).normalized()
var horizontal_velocity := player_body.up_plane.project(player_body.velocity)
var dir_forward := player_body.up_plane.project(left_to_right.rotated(player_body.up_vector, PI/2)).normalized()
var forward_velocity := dir_forward * glide_forward_speed
horizontal_velocity = lerp(horizontal_velocity, forward_velocity, horizontal_slew_rate * delta)

# Perform the glide
var glide_velocity := horizontal_velocity + vertical_velocity * Vector3.UP
var glide_velocity := horizontal_velocity + vertical_velocity * player_body.up_vector
player_body.velocity = player_body.move_body(glide_velocity)

# Report exclusive motion performed (to bypass gravity)
return true

# Rotate the origin node around the camera
func _rotate_player(player_body: XRToolsPlayerBody, angle: float):
var t1 := Transform()
var t2 := Transform()
var rot := Transform()

t1.origin = -player_body.camera_node.transform.origin
t2.origin = player_body.camera_node.transform.origin
rot = rot.rotated(Vector3(0.0, -1.0, 0.0), angle)
player_body.origin_node.transform = (player_body.origin_node.transform * t2 * rot * t1).orthonormalized()

# Set the gliding state and fire any signals
func _set_gliding(active: bool) -> void:
Expand Down
16 changes: 2 additions & 14 deletions addons/godot-xr-tools/functions/movement_turn.gd
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, _disabled: b

# Handle smooth rotation
if !_snap_turning():
_rotate_player(player_body, smooth_turn_speed * delta * left_right)
player_body.rotate_player(smooth_turn_speed * delta * left_right)
return

# Update the next turn-step delay
Expand All @@ -79,19 +79,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, _disabled: b

# Turn one step in the requested direction
_turn_step = step_turn_delay
_rotate_player(player_body, deg2rad(step_turn_angle) * sign(left_right))


# Rotate the origin node around the camera
func _rotate_player(player_body: XRToolsPlayerBody, angle: float):
var t1 := Transform()
var t2 := Transform()
var rot := Transform()

t1.origin = -player_body.camera_node.transform.origin
t2.origin = player_body.camera_node.transform.origin
rot = rot.rotated(Vector3(0.0, -1.0, 0.0), angle)
player_body.origin_node.transform = (player_body.origin_node.transform * t2 * rot * t1).orthonormalized()
player_body.rotate_player(deg2rad(step_turn_angle) * sign(left_right))


# This method verifies the movement provider has a valid configuration.
Expand Down
33 changes: 33 additions & 0 deletions addons/godot-xr-tools/functions/movement_wall_walk.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
tool
class_name XRToolsMovementWallWalk
extends XRToolsMovementProvider


## Wall walking provider order
export var order : int = 10

## Set our follow layer mask
export (int, LAYERS_3D_PHYSICS) var follow_mask : int = 1023

## Wall stick strength
export var stick_strength : float = 9.8



# Perform jump movement
func physics_movement(_delta: float, player_body: XRToolsPlayerBody, _disabled: bool):
# Skip if not in contact with ground
if not player_body.on_ground:
return

# Skip if the ground node doesn't have a collision layer
if not "collision_layer" in player_body.ground_node:
return

# Skip if the ground doesn't have the follow layer
var ground_layer : int = player_body.ground_node.collision_layer
if (ground_layer & follow_mask) == 0:
return

# Modify gravity to match the ground
player_body.gravity = player_body.ground_vector * -stick_strength
6 changes: 6 additions & 0 deletions addons/godot-xr-tools/functions/movement_wall_walk.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=2]

[ext_resource path="res://addons/godot-xr-tools/functions/movement_wall_walk.gd" type="Script" id=1]

[node name="MovementWallWalk" type="Node" groups=["movement_providers"]]
script = ExtResource( 1 )
Loading

0 comments on commit 49a49ea

Please sign in to comment.