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
  • Loading branch information
Malcolmnixon committed Dec 23, 2022
1 parent 05f7d20 commit f631ca9
Show file tree
Hide file tree
Showing 27 changed files with 911 additions and 150 deletions.
12 changes: 1 addition & 11 deletions addons/godot-xr-tools/functions/movement_glide.gd
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo

if turn_with_roll:
var angle = -left_to_right_vector.y
_rotate_player(player_body, roll_turn_speed * delta * angle)
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 @@ -119,16 +119,6 @@ func physics_movement(delta: float, player_body: XRToolsPlayerBody, disabled: bo
# 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
70 changes: 14 additions & 56 deletions addons/godot-xr-tools/functions/movement_provider.gd
Original file line number Diff line number Diff line change
@@ -1,78 +1,36 @@
tool
class_name XRToolsMovementProvider, "res://addons/godot-xr-tools/editor/icons/movement_provider.svg"
extends Node
extends XRToolsPlayerProvider


## XR Tools Movement Provider base class
##
## Movement Provider base class
## This movement provider class is the base class of all movement providers.
## Movement providers are invoked by the [XRToolsPlayerBody] object in order
## to apply motion to the player
##
## @desc:
## This movement provider class is the base class of all movement providers.
## Movement providers are invoked by the PlayerBody object in order to apply
## motion to the player
##
## Movement provider implementations should:
## - Export an 'order' integer to control order of processing
## - Override the physics_movement method to impelment motion
##

## Movement provider implementations should:
## - Export an 'order' integer to control order of processing
## - Override the physics_movement method to impelment motion

## Enable movement provider
export var enabled : bool = true


# Is the movement provider actively performing a move
## Is the movement provider actively performing a move
var is_active := false


# If missing we need to add our XRToolsPlayerBody
func _create_player_body_node():
# get our origin node
var arvr_origin := ARVRHelpers.get_arvr_origin(self)
if !arvr_origin:
return

# Double check if it hasn't already been created by another movement function
var player_body := XRToolsPlayerBody.find_instance(self)
if !player_body:
# create our XRToolsPlayerBody node and add it into our tree
var player_body_scene = preload("res://addons/godot-xr-tools/player/player_body.tscn")
player_body = player_body_scene.instance()
player_body.set_name("PlayerBody")
arvr_origin.add_child(player_body)
player_body.set_owner(get_tree().get_edited_scene_root())


# Add support for is_class on XRTools classes
## Add support for is_class on XRTools classes
func is_class(name : String) -> bool:
return name == "XRToolsMovementProvider" or .is_class(name)


# Function run when node is added to scene
func _ready():
# If we're in the editor, help the user out by creating our XRToolsPlayerBody node
# automatically when needed.
if Engine.editor_hint:
var player_body = XRToolsPlayerBody.find_instance(self)
if !player_body:
# This call needs to be deferred, we can't add nodes during scene construction
call_deferred("_create_player_body_node")


# Override this function to apply motion to the PlayerBody
## Override this function to apply motion to the PlayerBody
func physics_movement(_delta: float, _player_body: XRToolsPlayerBody, _disabled: bool):
pass


# This method verifies the movement provider has a valid configuration.
## This method verifies the movement provider has a valid configuration.
func _get_configuration_warning():
# Verify we're within the tree of an ARVROrigin node
if !ARVRHelpers.get_arvr_origin(self):
return "This node must be within a branch on an ARVROrigin node"

if !XRToolsPlayerBody.find_instance(self):
return "Missing PlayerBody node on the ARVROrigin"

# Verify movement provider is in the correct group
if !is_in_group("movement_providers"):
return "Movement provider not in 'movement_providers' group"
Expand All @@ -81,5 +39,5 @@ func _get_configuration_warning():
if !"order" in self:
return "Movement provider does not expose an order property"

# Passed basic validation
return ""
# Call base class
return ._get_configuration_warning()
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
106 changes: 106 additions & 0 deletions addons/godot-xr-tools/functions/orientation_area.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
tool
class_name XRToolsOrientationArea
extends XRToolsOrientationProvider


## XR Tools Area Orientation Provider
##
## This orientation provider orients the player based on orient areas the player
## enters.


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

# Set our collision mask
export (int, LAYERS_3D_PHYSICS) var collision_mask : int = 524288


# Orient sense area
var _sense_area : Area

# Array of orientation areas the player is in
var _orient_areas := Array()


# Add support for is_class on XRTools classes
func is_class(name : String) -> bool:
return name == "XRToolsOrientationArea" or .is_class(name)


# Called when the node enters the scene tree for the first time.
func _ready():
# Skip if running in the editor
if Engine.editor_hint:
return

# Skip if we don't have a player
var player := XRToolsPlayerBody.find_instance(self)
if !player:
return

# Construct the sphere shape
var sphere_shape := SphereShape.new()
sphere_shape.radius = 0.3

# Construct the collision shape
var collision_shape := CollisionShape.new()
collision_shape.set_name("OrientSensorShape")
collision_shape.shape = sphere_shape

# Construct the sense area
_sense_area = Area.new()
_sense_area.set_name("OrientSensorArea")
_sense_area.collision_mask = collision_mask
_sense_area.add_child(collision_shape)

# Add the sense area to the players body (feet)
player.kinematic_node.add_child(_sense_area)

# Subscribe to area notifications
_sense_area.connect("area_entered", self, "_on_area_entered")
_sense_area.connect("area_exited", self, "_on_area_exited")


## Perform player orientation to ground
func physics_orientation(_delta: float, _player_body: XRToolsPlayerBody) -> bool:
# Skip if not in any orient areas
if _orient_areas.size() == 0:
return false

# Get the highest priority area
var area : XRToolsOrientArea = _orient_areas.front()

# If enabled, override player gravity
if area.override_player_gravity:
_player_body.gravity = area.player_gravity

# Get the up vector and orient the player
var up := area.get_up(_player_body.kinematic_node.global_translation)
_player_body.slew_up(up, _delta * area.slew_rate)
return true


func _on_area_entered(area: Area):
# Skip if not orient area
var orient_area = area as XRToolsOrientArea
if !orient_area:
return

# Iterate over all areas in the list
for pos in _orient_areas.size():
# Get the area in the list
var a : XRToolsOrientArea = _orient_areas[pos]

# Insert before lower priorities
if a.priority <= orient_area.priority:
_orient_areas.insert(pos, orient_area)
return

# Insert at the end
_orient_areas.push_back(orient_area)


func _on_area_exited(area: Area):
# Erase the area from the list
_orient_areas.erase(area)
6 changes: 6 additions & 0 deletions addons/godot-xr-tools/functions/orientation_area.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/orientation_area.gd" type="Script" id=1]

[node name="OrientationArea" type="Node" groups=["orientation_providers"]]
script = ExtResource( 1 )
49 changes: 49 additions & 0 deletions addons/godot-xr-tools/functions/orientation_ground.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
tool
class_name XRToolsOrientationGround
extends XRToolsOrientationProvider


## XR Tools Ground Orientation Provider
##
## This ground orientation provider orients the player on any ground surface
## whose physics layer matches the follow mask


## Orientation provider order
export var order : int = 10

## Slew rate when on ground
export var ground_slew_rate : float = 5.0

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

## If true, player gravity is modified when the player touches the ground
export var override_player_gravity : bool = false

## Player gravity
export var player_gravity : float = -9.8


## Perform player orientation to ground
func physics_orientation(_delta: float, _player_body: XRToolsPlayerBody) -> bool:
# Skip if not in contact with ground
if not _player_body.on_ground:
return false

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

# 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 false

# Override player gravity if requested
if override_player_gravity:
_player_body.gravity = player_gravity

# Slew the player to align with the ground
_player_body.slew_up(_player_body.ground_vector, _delta * ground_slew_rate)
return true
6 changes: 6 additions & 0 deletions addons/godot-xr-tools/functions/orientation_ground.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/orientation_ground.gd" type="Script" id=1]

[node name="OrientationGround" type="Node" groups=["orientation_providers"]]
script = ExtResource( 1 )
34 changes: 34 additions & 0 deletions addons/godot-xr-tools/functions/orientation_provider.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
tool
class_name XRToolsOrientationProvider, "res://addons/godot-xr-tools/editor/icons/node.svg"
extends XRToolsPlayerProvider


## XR Tools Orientation Provider base class
##
## This orientation provider class is the base class of all orientation
## providers. Orientation providers are invoked by the [XRToolsPlayerBody]
## object in order to orient the players up direction in the world.


## Add support for is_class on XRTools classes
func is_class(name : String) -> bool:
return name == "XRToolsOrientationProvider" or .is_class(name)


## Override this function to apply orientation to the PlayerBody
func physics_orientation(_delta: float, _player_body: XRToolsPlayerBody) -> bool:
return false


## This method verifies the movement provider has a valid configuration.
func _get_configuration_warning():
# Verify orientation provider is in the correct group
if !is_in_group("orientation_providers"):
return "Orientation provider not in 'orientation_providers' group"

# Verify order property exists
if !"order" in self:
return "Orientation provider does not expose an order property"

# Call base class
return ._get_configuration_warning()
30 changes: 30 additions & 0 deletions addons/godot-xr-tools/objects/orient/orient_area.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
tool
class_name XRToolsOrientArea, "res://addons/godot-xr-tools/editor/icons/node.svg"
extends Area


## XR Tools Orient Area base class
##
## This is the base class for orient areas which affect the players orientation.
## The player must have an [XRToolsOrientationArea] provider attached for
## orient areas to be processed.


## Slew rate for setting orientation
export var slew_rate : float = 5.0

## If true, player gravity is modified when the player enters the area
export var override_player_gravity : bool = false

## Player gravity
export var player_gravity : float = -9.8


## Add support for is_class on XRTools classes
func is_class(name : String) -> bool:
return name == "XRToolsOrientationArea" or .is_class(name)


## Get the up vector for the specified position
func get_up(_position: Vector3) -> Vector3:
return Vector3.UP
Loading

0 comments on commit f631ca9

Please sign in to comment.