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.

Modified XRToolsPlayerBody to split "up" into "up_player" and "up_gravity" as both are needed in different circumstances. Added physics_pre_movement() method to movement providers to let them perform initial service actions such as messing with gravity. Modified wall_walk movement to check for walking walls, and to modify the gravity to point to them.
  • Loading branch information
Malcolmnixon committed Dec 24, 2022
1 parent 05f7d20 commit 79b489d
Show file tree
Hide file tree
Showing 28 changed files with 884 additions and 168 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_player_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_player_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_player_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_player_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_player_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_player_plane.project(left_to_right.rotated(player_body.up_player_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_player_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_gravity_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_player_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_gravity_plane.project(player_body.velocity)
var dir_forward := player_body.up_gravity_plane.project(left_to_right.rotated(player_body.up_gravity_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_gravity_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
2 changes: 1 addition & 1 deletion addons/godot-xr-tools/functions/movement_grapple.gd
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo
var hook_direction := hook_vector / hook_length

# Apply gravity
player_body.velocity += Vector3.UP * player_body.gravity * delta
player_body.velocity += player_body.gravity * delta

# Select the grapple speed
var speed := impulse_speed if do_impulse else winch_speed
Expand Down
5 changes: 5 additions & 0 deletions addons/godot-xr-tools/functions/movement_provider.gd
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ func _ready():
call_deferred("_create_player_body_node")


# Override this function to perform pre-movement updates to the PlayerBody
func physics_pre_movement(_delta: float, _player_body: XRToolsPlayerBody):
pass


# Override this function to apply motion to the PlayerBody
func physics_movement(_delta: float, _player_body: XRToolsPlayerBody, _disabled: bool):
pass
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
41 changes: 41 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,41 @@
tool
class_name XRToolsMovementWallWalk
extends XRToolsMovementProvider


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

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

## Wall stick distance
export var stick_distance : float = 1.0

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



func physics_pre_movement(delta: float, player_body: XRToolsPlayerBody):
# Test for collision with wall under feet
var wall_collision := player_body.kinematic_node.move_and_collide(
player_body.up_player_vector * -stick_distance, true, true, true)
if !wall_collision:
return

# Get the wall information
var wall_node := wall_collision.collider
var wall_normal := wall_collision.normal

# Skip if the wall node doesn't have a collision layer
if not "collision_layer" in wall_node:
return

# Skip if the wall doesn't match the follow layer
var wall_layer : int = wall_node.collision_layer
if (wall_layer & follow_mask) == 0:
return

# Modify the player gravity
player_body.gravity = -wall_normal * 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 79b489d

Please sign in to comment.