init
This commit is contained in:
54
addons/godot-xr-tools/desktop-support/controller_hider.gd
Normal file
54
addons/godot-xr-tools/desktop-support/controller_hider.gd
Normal file
@@ -0,0 +1,54 @@
|
||||
@tool
|
||||
@icon("res://addons/godot-xr-tools/editor/icons/function.svg")
|
||||
class_name XRToolsDesktopControllerHider
|
||||
extends Node
|
||||
|
||||
## XR Tools Controller Hider
|
||||
##
|
||||
## This script hides controller if XR is not active.
|
||||
|
||||
var _pointer_disabler := false
|
||||
var _last_xr_active := true
|
||||
# XRStart node
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
|
||||
# Parent controller
|
||||
@onready var _controller : XRController3D = XRHelpers.get_xr_controller(self)
|
||||
|
||||
func _ready() -> void:
|
||||
if get_parent().has_method("is_xr_class"):
|
||||
if get_parent().is_xr_class("XRToolsFunctionPointer"):
|
||||
_pointer_disabler = true
|
||||
if get_parent() is XRToolsFunctionPointer:
|
||||
_pointer_disabler = true
|
||||
|
||||
# Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsDesktopControllerHider"
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if Engine.is_editor_hint() or !is_inside_tree():
|
||||
return
|
||||
if xr_start_node.is_xr_active()==_last_xr_active:
|
||||
return
|
||||
if _pointer_disabler:
|
||||
get_parent().enabled=xr_start_node.is_xr_active()
|
||||
elif is_instance_valid(_controller):
|
||||
_controller.visible=xr_start_node.is_xr_active()
|
||||
_last_xr_active=xr_start_node.is_xr_active()
|
||||
|
||||
|
||||
# This method verifies the movement provider has a valid configuration.
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var warnings := PackedStringArray()
|
||||
|
||||
# Check the controller node
|
||||
if !XRHelpers.get_xr_controller(self) \
|
||||
and !XRTools.find_xr_ancestor(self,"*","XRToolsFunctionPointer"):
|
||||
warnings.append("This node must be within a branch of an XRController3D node")
|
||||
|
||||
# Return warnings
|
||||
return warnings
|
||||
@@ -0,0 +1 @@
|
||||
uid://hyiqt6os3ud6
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://chb848dtavews"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://hyiqt6os3ud6" path="res://addons/godot-xr-tools/desktop-support/controller_hider.gd" id="1_6xusf"]
|
||||
|
||||
[node name="ControllerHider" type="Node"]
|
||||
script = ExtResource("1_6xusf")
|
||||
@@ -0,0 +1,484 @@
|
||||
@tool
|
||||
@icon("res://addons/godot-xr-tools/editor/icons/function.svg")
|
||||
class_name XRToolsDesktopFunctionPointer
|
||||
extends Node3D
|
||||
|
||||
|
||||
## XR Tools Function Pointer Script
|
||||
##
|
||||
## This script implements a pointer function for a players controller. Pointer
|
||||
## events (entered, exited, pressed, release, and movement) are delivered by
|
||||
## invoking signals on the target node.
|
||||
##
|
||||
## Pointer target nodes commonly extend from [XRToolsInteractableArea] or
|
||||
## [XRToolsInteractableBody].
|
||||
|
||||
|
||||
## Signal emitted when this object points at another object
|
||||
signal pointing_event(event)
|
||||
|
||||
|
||||
## Enumeration of laser show modes
|
||||
enum LaserShow {
|
||||
HIDE = 0, ## Hide laser
|
||||
SHOW = 1, ## Show laser
|
||||
COLLIDE = 2, ## Only show laser on collision
|
||||
}
|
||||
|
||||
## Enumeration of laser length modes
|
||||
enum LaserLength {
|
||||
FULL = 0, ## Full length
|
||||
COLLIDE = 1 ## Draw to collision
|
||||
}
|
||||
|
||||
|
||||
## Default pointer collision mask of 21:pointable and 23:ui-objects
|
||||
const DEFAULT_MASK := 0b0000_0000_0101_0000_0000_0000_0000_0000
|
||||
|
||||
## Default pointer collision mask of 23:ui-objects
|
||||
const SUPPRESS_MASK := 0b0000_0000_0100_0000_0000_0000_0000_0000
|
||||
|
||||
|
||||
@export_group("General")
|
||||
|
||||
## Pointer enabled
|
||||
@export var enabled : bool = true: set = set_enabled
|
||||
|
||||
## Y Offset for pointer
|
||||
@export var y_offset : float = -0.013: set = set_y_offset
|
||||
|
||||
## Pointer distance
|
||||
@export var distance : float = 10: set = set_distance
|
||||
|
||||
## Active button action
|
||||
@export var active_button_action : String = "trigger_click"
|
||||
|
||||
@export_group("Laser")
|
||||
|
||||
## Controls when the laser is visible
|
||||
@export var show_laser : LaserShow = LaserShow.SHOW: set = set_show_laser
|
||||
|
||||
## Controls the length of the laser
|
||||
@export var laser_length : LaserLength = LaserLength.FULL: set = set_laser_length
|
||||
|
||||
## Laser pointer material
|
||||
@export var laser_material : StandardMaterial3D = null : set = set_laser_material
|
||||
|
||||
## Laser pointer material when hitting target
|
||||
@export var laser_hit_material : StandardMaterial3D = null : set = set_laser_hit_material
|
||||
|
||||
@export_group("Target")
|
||||
|
||||
## If true, the pointer target is shown
|
||||
@export var show_target : bool = false: set = set_show_target
|
||||
|
||||
## Controls the target radius
|
||||
@export var target_radius : float = 0.05: set = set_target_radius
|
||||
|
||||
## Target material
|
||||
@export var target_material : StandardMaterial3D = null : set = set_target_material
|
||||
|
||||
@export_group("Collision")
|
||||
|
||||
## Pointer collision mask
|
||||
@export_flags_3d_physics var collision_mask : int = DEFAULT_MASK: set = set_collision_mask
|
||||
|
||||
## Enable pointer collision with bodies
|
||||
@export var collide_with_bodies : bool = true: set = set_collide_with_bodies
|
||||
|
||||
## Enable pointer collision with areas
|
||||
@export var collide_with_areas : bool = false: set = set_collide_with_areas
|
||||
|
||||
@export_group("Suppression")
|
||||
|
||||
## Suppress radius
|
||||
@export var suppress_radius : float = 0.2: set = set_suppress_radius
|
||||
|
||||
## Suppress mask
|
||||
@export_flags_3d_physics var suppress_mask : int = SUPPRESS_MASK: set = set_suppress_mask
|
||||
|
||||
|
||||
## Current target node
|
||||
var target : Node3D = null
|
||||
|
||||
## Last target node
|
||||
var last_target : Node3D = null
|
||||
|
||||
## Last collision point
|
||||
var last_collided_at : Vector3 = Vector3.ZERO
|
||||
|
||||
# World scale
|
||||
var _world_scale : float = 1.0
|
||||
|
||||
# XRStart Node
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
|
||||
## Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsDesktopFunctionPointer"
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
# Do not initialise if in the editor
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
# Read the initial world-scale
|
||||
_world_scale = XRServer.world_scale
|
||||
|
||||
# init our state
|
||||
_update_y_offset()
|
||||
_update_distance()
|
||||
_update_pointer()
|
||||
_update_target_radius()
|
||||
_update_target_material()
|
||||
_update_collision_mask()
|
||||
_update_collide_with_bodies()
|
||||
_update_collide_with_areas()
|
||||
_update_suppress_radius()
|
||||
_update_suppress_mask()
|
||||
|
||||
# Called on each frame to update the pickup
|
||||
func _process(_delta):
|
||||
# Do not process if in the editor
|
||||
if Engine.is_editor_hint() or !is_inside_tree():
|
||||
return
|
||||
|
||||
# Handle world-scale changes
|
||||
var new_world_scale := XRServer.world_scale
|
||||
if (_world_scale != new_world_scale):
|
||||
_world_scale = new_world_scale
|
||||
_update_y_offset()
|
||||
set_enabled(!xr_start_node.is_xr_active())
|
||||
|
||||
if Input.is_action_just_released(active_button_action):
|
||||
_on_button_pressed(active_button_action)
|
||||
await get_tree().process_frame
|
||||
_on_button_released(active_button_action)
|
||||
|
||||
# Find the new pointer target
|
||||
var new_target : Node3D
|
||||
var new_at : Vector3
|
||||
var suppress_area := $SuppressArea
|
||||
if (enabled and
|
||||
not $SuppressArea.has_overlapping_bodies() and
|
||||
not $SuppressArea.has_overlapping_areas() and
|
||||
$RayCast.is_colliding()):
|
||||
new_at = $RayCast.get_collision_point()
|
||||
if target:
|
||||
# Locked to 'target' even if we're colliding with something else
|
||||
new_target = target
|
||||
else:
|
||||
# Target is whatever the raycast is colliding with
|
||||
new_target = $RayCast.get_collider()
|
||||
|
||||
# If no current or previous collisions then skip
|
||||
if not new_target and not last_target:
|
||||
return
|
||||
|
||||
# Handle pointer changes
|
||||
if new_target and not last_target:
|
||||
# Pointer entered new_target
|
||||
XRToolsPointerEvent.entered(self, new_target, new_at)
|
||||
|
||||
# Pointer moved on new_target for the first time
|
||||
XRToolsPointerEvent.moved(self, new_target, new_at, new_at)
|
||||
|
||||
# Update visible artifacts for hit
|
||||
_visible_hit(new_at)
|
||||
elif not new_target and last_target:
|
||||
# Pointer exited last_target
|
||||
XRToolsPointerEvent.exited(self, last_target, last_collided_at)
|
||||
|
||||
# Update visible artifacts for miss
|
||||
_visible_miss()
|
||||
elif new_target != last_target:
|
||||
# Pointer exited last_target
|
||||
XRToolsPointerEvent.exited(self, last_target, last_collided_at)
|
||||
|
||||
# Pointer entered new_target
|
||||
XRToolsPointerEvent.entered(self, new_target, new_at)
|
||||
|
||||
# Pointer moved on new_target
|
||||
XRToolsPointerEvent.moved(self, new_target, new_at, new_at)
|
||||
|
||||
# Move visible artifacts
|
||||
_visible_move(new_at)
|
||||
elif new_at != last_collided_at:
|
||||
# Pointer moved on new_target
|
||||
XRToolsPointerEvent.moved(self, new_target, new_at, last_collided_at)
|
||||
|
||||
# Move visible artifacts
|
||||
_visible_move(new_at)
|
||||
|
||||
# Update last values
|
||||
last_target = new_target
|
||||
last_collided_at = new_at
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var warnings := PackedStringArray()
|
||||
|
||||
# Check the controller node
|
||||
if !XRTools.find_xr_ancestor(self,"*","XRCamera3D"):
|
||||
warnings.append("This node must be within a branch of an XRCamera3D node")
|
||||
|
||||
# Return warnings
|
||||
return warnings
|
||||
|
||||
# Set pointer enabled property
|
||||
func set_enabled(p_enabled : bool) -> void:
|
||||
enabled = p_enabled
|
||||
if is_inside_tree():
|
||||
_update_pointer()
|
||||
|
||||
|
||||
# Set pointer y_offset property
|
||||
func set_y_offset(p_offset : float) -> void:
|
||||
y_offset = p_offset
|
||||
if is_inside_tree():
|
||||
_update_y_offset()
|
||||
|
||||
|
||||
# Set pointer distance property
|
||||
func set_distance(p_new_value : float) -> void:
|
||||
distance = p_new_value
|
||||
if is_inside_tree():
|
||||
_update_distance()
|
||||
|
||||
|
||||
# Set pointer show_laser property
|
||||
func set_show_laser(p_show : LaserShow) -> void:
|
||||
show_laser = p_show
|
||||
if is_inside_tree():
|
||||
_update_pointer()
|
||||
|
||||
|
||||
# Set pointer laser_length property
|
||||
func set_laser_length(p_laser_length : LaserLength) -> void:
|
||||
laser_length = p_laser_length
|
||||
if is_inside_tree():
|
||||
_update_pointer()
|
||||
|
||||
|
||||
# Set pointer laser_material property
|
||||
func set_laser_material(p_laser_material : StandardMaterial3D) -> void:
|
||||
laser_material = p_laser_material
|
||||
if is_inside_tree():
|
||||
_update_pointer()
|
||||
|
||||
|
||||
# Set pointer laser_hit_material property
|
||||
func set_laser_hit_material(p_laser_hit_material : StandardMaterial3D) -> void:
|
||||
laser_hit_material = p_laser_hit_material
|
||||
if is_inside_tree():
|
||||
_update_pointer()
|
||||
|
||||
|
||||
# Set pointer show_target property
|
||||
func set_show_target(p_show_target : bool) -> void:
|
||||
show_target = p_show_target
|
||||
if is_inside_tree():
|
||||
$Target.visible = enabled and show_target and last_target
|
||||
|
||||
|
||||
# Set pointer target_radius property
|
||||
func set_target_radius(p_target_radius : float) -> void:
|
||||
target_radius = p_target_radius
|
||||
if is_inside_tree():
|
||||
_update_target_radius()
|
||||
|
||||
|
||||
# Set pointer target_material property
|
||||
func set_target_material(p_target_material : StandardMaterial3D) -> void:
|
||||
target_material = p_target_material
|
||||
if is_inside_tree():
|
||||
_update_target_material()
|
||||
|
||||
|
||||
# Set pointer collision_mask property
|
||||
func set_collision_mask(p_new_mask : int) -> void:
|
||||
collision_mask = p_new_mask
|
||||
if is_inside_tree():
|
||||
_update_collision_mask()
|
||||
|
||||
|
||||
# Set pointer collide_with_bodies property
|
||||
func set_collide_with_bodies(p_new_value : bool) -> void:
|
||||
collide_with_bodies = p_new_value
|
||||
if is_inside_tree():
|
||||
_update_collide_with_bodies()
|
||||
|
||||
|
||||
# Set pointer collide_with_areas property
|
||||
func set_collide_with_areas(p_new_value : bool) -> void:
|
||||
collide_with_areas = p_new_value
|
||||
if is_inside_tree():
|
||||
_update_collide_with_areas()
|
||||
|
||||
|
||||
# Set suppress radius property
|
||||
func set_suppress_radius(p_suppress_radius : float) -> void:
|
||||
suppress_radius = p_suppress_radius
|
||||
if is_inside_tree():
|
||||
_update_suppress_radius()
|
||||
|
||||
|
||||
func set_suppress_mask(p_suppress_mask : int) -> void:
|
||||
suppress_mask = p_suppress_mask
|
||||
if is_inside_tree():
|
||||
_update_suppress_mask()
|
||||
|
||||
|
||||
# Pointer Y offset update handler
|
||||
func _update_y_offset() -> void:
|
||||
$Laser.position.y = y_offset * _world_scale
|
||||
$RayCast.position.y = y_offset * _world_scale
|
||||
|
||||
|
||||
# Pointer distance update handler
|
||||
func _update_distance() -> void:
|
||||
$RayCast.target_position.z = -distance
|
||||
_update_pointer()
|
||||
|
||||
|
||||
# Pointer target radius update handler
|
||||
func _update_target_radius() -> void:
|
||||
$Target.mesh.radius = target_radius
|
||||
$Target.mesh.height = target_radius * 2
|
||||
|
||||
|
||||
# Pointer target_material update handler
|
||||
func _update_target_material() -> void:
|
||||
$Target.set_surface_override_material(0, target_material)
|
||||
|
||||
|
||||
# Pointer collision_mask update handler
|
||||
func _update_collision_mask() -> void:
|
||||
$RayCast.collision_mask = collision_mask
|
||||
|
||||
|
||||
# Pointer collide_with_bodies update handler
|
||||
func _update_collide_with_bodies() -> void:
|
||||
$RayCast.collide_with_bodies = collide_with_bodies
|
||||
|
||||
|
||||
# Pointer collide_with_areas update handler
|
||||
func _update_collide_with_areas() -> void:
|
||||
$RayCast.collide_with_areas = collide_with_areas
|
||||
|
||||
|
||||
# Pointer suppress_radius update handler
|
||||
func _update_suppress_radius() -> void:
|
||||
$SuppressArea/CollisionShape3D.shape.radius = suppress_radius
|
||||
|
||||
|
||||
# Pointer suppress_mask update handler
|
||||
func _update_suppress_mask() -> void:
|
||||
$SuppressArea.collision_mask = suppress_mask
|
||||
|
||||
|
||||
# Pointer visible artifacts update handler
|
||||
func _update_pointer() -> void:
|
||||
if enabled and last_target:
|
||||
_visible_hit(last_collided_at)
|
||||
else:
|
||||
_visible_miss()
|
||||
|
||||
|
||||
# Pointer-activation button pressed handler
|
||||
func _button_pressed() -> void:
|
||||
if $RayCast.is_colliding():
|
||||
# Report pressed
|
||||
target = $RayCast.get_collider()
|
||||
last_collided_at = $RayCast.get_collision_point()
|
||||
XRToolsPointerEvent.pressed(self, target, last_collided_at)
|
||||
|
||||
|
||||
# Pointer-activation button released handler
|
||||
func _button_released() -> void:
|
||||
if target:
|
||||
# Report release
|
||||
XRToolsPointerEvent.released(self, target, last_collided_at)
|
||||
target = null
|
||||
last_collided_at = Vector3(0, 0, 0)
|
||||
|
||||
|
||||
# Button pressed handler
|
||||
func _on_button_pressed(p_button : String) -> void:
|
||||
if p_button == active_button_action and enabled:
|
||||
_button_pressed()
|
||||
|
||||
|
||||
# Button released handler
|
||||
func _on_button_released(p_button : String) -> void:
|
||||
if p_button == active_button_action and target:
|
||||
_button_released()
|
||||
|
||||
|
||||
# Update the laser active material
|
||||
func _update_laser_active_material(hit : bool) -> void:
|
||||
if hit and laser_hit_material:
|
||||
$Laser.set_surface_override_material(0, laser_hit_material)
|
||||
else:
|
||||
$Laser.set_surface_override_material(0, laser_material)
|
||||
|
||||
|
||||
# Update the visible artifacts to show a hit
|
||||
func _visible_hit(at : Vector3) -> void:
|
||||
# Show target if enabled
|
||||
if show_target:
|
||||
$Target.global_transform.origin = at
|
||||
$Target.visible = true
|
||||
|
||||
# Control laser visibility
|
||||
if show_laser != LaserShow.HIDE:
|
||||
# Ensure the correct laser material is set
|
||||
_update_laser_active_material(true)
|
||||
|
||||
# Adjust laser length
|
||||
if laser_length == LaserLength.COLLIDE:
|
||||
var collide_len : float = at.distance_to(global_transform.origin)
|
||||
$Laser.mesh.size.z = collide_len
|
||||
$Laser.position.z = collide_len * -0.5
|
||||
else:
|
||||
$Laser.mesh.size.z = distance
|
||||
$Laser.position.z = distance * -0.5
|
||||
|
||||
# Show laser
|
||||
$Laser.visible = true
|
||||
else:
|
||||
# Ensure laser is hidden
|
||||
$Laser.visible = false
|
||||
|
||||
|
||||
# Move the visible pointer artifacts to the target
|
||||
func _visible_move(at : Vector3) -> void:
|
||||
# Move target if configured
|
||||
if show_target:
|
||||
$Target.global_transform.origin = at
|
||||
|
||||
# Adjust laser length if set to collide-length
|
||||
if laser_length == LaserLength.COLLIDE:
|
||||
var collide_len : float = at.distance_to(global_transform.origin)
|
||||
$Laser.mesh.size.z = collide_len
|
||||
$Laser.position.z = collide_len * -0.5
|
||||
|
||||
|
||||
# Update the visible artifacts to show a miss
|
||||
func _visible_miss() -> void:
|
||||
# Ensure target is hidden
|
||||
$Target.visible = false
|
||||
|
||||
# Ensure the correct laser material is set
|
||||
_update_laser_active_material(false)
|
||||
|
||||
# Hide laser if not set to show always
|
||||
$Laser.visible = show_laser == LaserShow.SHOW
|
||||
|
||||
# Restore laser length if set to collide-length
|
||||
$Laser.mesh.size.z = distance
|
||||
$Laser.position.z = distance * -0.5
|
||||
@@ -0,0 +1 @@
|
||||
uid://dycttwespa005
|
||||
@@ -0,0 +1,51 @@
|
||||
[gd_scene load_steps=6 format=3 uid="uid://42xbeno6pt3y"]
|
||||
|
||||
[ext_resource type="Material" path="res://addons/godot-xr-tools/materials/pointer.tres" id="1"]
|
||||
[ext_resource type="Script" uid="uid://dycttwespa005" path="res://addons/godot-xr-tools/desktop-support/function_desktop_pointer.gd" id="1_fkfo7"]
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_ctrty"]
|
||||
resource_local_to_scene = true
|
||||
material = ExtResource("1")
|
||||
size = Vector3(0.002, 0.002, 10)
|
||||
subdivide_depth = 20
|
||||
|
||||
[sub_resource type="SphereMesh" id="SphereMesh_6cghy"]
|
||||
material = ExtResource("1")
|
||||
radius = 0.01
|
||||
height = 0.02
|
||||
radial_segments = 16
|
||||
rings = 8
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_8btxb"]
|
||||
radius = 0.2
|
||||
|
||||
[node name="FunctionDesktopPointer" type="Node3D"]
|
||||
script = ExtResource("1_fkfo7")
|
||||
y_offset = 0.0
|
||||
active_button_action = "trigger_left"
|
||||
show_laser = 0
|
||||
laser_length = 1
|
||||
show_target = true
|
||||
target_radius = 0.01
|
||||
|
||||
[node name="RayCast" type="RayCast3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, 0)
|
||||
target_position = Vector3(0, 0, -10)
|
||||
collision_mask = 5242880
|
||||
|
||||
[node name="Laser" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, -5)
|
||||
visible = false
|
||||
cast_shadow = 0
|
||||
mesh = SubResource("BoxMesh_ctrty")
|
||||
|
||||
[node name="Target" type="MeshInstance3D" parent="."]
|
||||
visible = false
|
||||
mesh = SubResource("SphereMesh_6cghy")
|
||||
|
||||
[node name="SuppressArea" type="Area3D" parent="."]
|
||||
collision_layer = 0
|
||||
collision_mask = 4194304
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="SuppressArea"]
|
||||
shape = SubResource("SphereShape3D_8btxb")
|
||||
50
addons/godot-xr-tools/desktop-support/mouse_capture.gd
Normal file
50
addons/godot-xr-tools/desktop-support/mouse_capture.gd
Normal file
@@ -0,0 +1,50 @@
|
||||
@tool
|
||||
class_name XRToolsDesktopMouseCapture
|
||||
extends XRToolsMovementProvider
|
||||
|
||||
## XR Tools Mouse Capture
|
||||
##
|
||||
## This script provides support for desktop mouse capture. This script works
|
||||
## with the PlayerBody attached to the players XROrigin3D.
|
||||
|
||||
|
||||
## Movement provider order
|
||||
@export var order : int = 1
|
||||
|
||||
## Our directional input
|
||||
@export var escape_action : String = "ui_cancel"
|
||||
|
||||
#Last mouse capture status and should it be auto captured
|
||||
@export var capture : bool = true
|
||||
|
||||
|
||||
# XRStart node
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
|
||||
|
||||
# Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsDesktopMouseCapture" or super(xr_name)
|
||||
|
||||
|
||||
# Perform jump movement
|
||||
func physics_movement(_delta: float, player_body: XRToolsPlayerBody, _disabled: bool):
|
||||
# Skip if the player body isn't active
|
||||
var check1 :bool= (xr_start_node.is_xr_active() and Input.mouse_mode==Input.MOUSE_MODE_CAPTURED)
|
||||
if !player_body.enabled or check1:
|
||||
return
|
||||
|
||||
|
||||
if Input.is_action_just_pressed("ui_cancel"):
|
||||
capture=!capture
|
||||
|
||||
#print(Input.mouse_mode==Input.MOUSE_MODE_CAPTURED)
|
||||
|
||||
if Input.mouse_mode==Input.MOUSE_MODE_CAPTURED and (xr_start_node.is_xr_active() or !capture):
|
||||
Input.mouse_mode=Input.MOUSE_MODE_VISIBLE
|
||||
elif (!xr_start_node.is_xr_active() and capture):
|
||||
Input.mouse_mode=Input.MOUSE_MODE_CAPTURED
|
||||
return
|
||||
@@ -0,0 +1 @@
|
||||
uid://71ls6bjad8tp
|
||||
6
addons/godot-xr-tools/desktop-support/mouse_capture.tscn
Normal file
6
addons/godot-xr-tools/desktop-support/mouse_capture.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://bkse5rxsx5tb3"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://71ls6bjad8tp" path="res://addons/godot-xr-tools/desktop-support/mouse_capture.gd" id="1_po4v8"]
|
||||
|
||||
[node name="MouseCapture" type="Node3D" groups=["movement_providers"]]
|
||||
script = ExtResource("1_po4v8")
|
||||
@@ -0,0 +1,83 @@
|
||||
@tool
|
||||
class_name XRToolsDesktopMovementCrouch
|
||||
extends XRToolsMovementProvider
|
||||
|
||||
|
||||
## XR Tools Movement Provider for Crouching
|
||||
##
|
||||
## This script works with the [XRToolsPlayerBody] attached to the players
|
||||
## [XROrigin3D].
|
||||
##
|
||||
## While the player presses the crounch button, the height is overridden to
|
||||
## the specified crouch height.
|
||||
|
||||
|
||||
## Enumeration of crouching modes
|
||||
enum CrouchType {
|
||||
HOLD_TO_CROUCH, ## Hold button to crouch
|
||||
TOGGLE_CROUCH, ## Toggle crouching on button press
|
||||
}
|
||||
|
||||
|
||||
## Movement provider order
|
||||
@export var order : int = 10
|
||||
|
||||
## Crouch height
|
||||
@export var crouch_height : float = 1.0
|
||||
|
||||
## Crouch button
|
||||
@export var crouch_button_action : String = "action_crouch"
|
||||
|
||||
## Type of crouching
|
||||
@export var crouch_type : CrouchType = CrouchType.HOLD_TO_CROUCH
|
||||
|
||||
|
||||
## Crouching flag
|
||||
var _crouching : bool = false
|
||||
|
||||
## Crouch button down state
|
||||
var _crouch_button_down : bool = false
|
||||
|
||||
|
||||
# Controller node
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
|
||||
|
||||
# Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsMovementCrouch" or super(xr_name)
|
||||
|
||||
|
||||
# Perform jump movement
|
||||
func physics_movement(_delta: float, player_body: XRToolsPlayerBody, _disabled: bool):
|
||||
# Skip if the controller isn't active
|
||||
if !player_body.enabled or xr_start_node.is_xr_active():
|
||||
return
|
||||
|
||||
# Detect crouch button down and pressed states
|
||||
var crouch_button_down := Input.is_action_pressed(crouch_button_action)
|
||||
var crouch_button_pressed := crouch_button_down and !_crouch_button_down
|
||||
_crouch_button_down = crouch_button_down
|
||||
|
||||
# Calculate new crouching state
|
||||
var crouching := _crouching
|
||||
match crouch_type:
|
||||
CrouchType.HOLD_TO_CROUCH:
|
||||
# Crouch when button down
|
||||
crouching = crouch_button_down
|
||||
|
||||
CrouchType.TOGGLE_CROUCH:
|
||||
# Toggle when button pressed
|
||||
if crouch_button_pressed:
|
||||
crouching = !crouching
|
||||
|
||||
# Update crouching state
|
||||
if crouching != _crouching:
|
||||
_crouching = crouching
|
||||
if crouching:
|
||||
player_body.override_player_height(self, crouch_height)
|
||||
else:
|
||||
player_body.override_player_height(self)
|
||||
@@ -0,0 +1 @@
|
||||
uid://onavg33r434i
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://d2iqcc25yvk61"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://onavg33r434i" path="res://addons/godot-xr-tools/desktop-support/movement_desktop_crouch.gd" id="1_4rbnc"]
|
||||
|
||||
[node name="MovementDesktopCrouch" type="Node3D" groups=["movement_providers"]]
|
||||
script = ExtResource("1_4rbnc")
|
||||
@@ -0,0 +1,72 @@
|
||||
@tool
|
||||
class_name XRToolsDesktopMovementDirect
|
||||
extends XRToolsMovementProvider
|
||||
|
||||
|
||||
## XR Tools Movement Provider for Direct Movement
|
||||
##
|
||||
## This script provides direct movement for the player. This script works
|
||||
## with the [XRToolsPlayerBody] attached to the players [XROrigin3D].
|
||||
##
|
||||
## The player may have multiple [XRToolsMovementDirect] nodes attached to
|
||||
## different controllers to provide different types of direct movement.
|
||||
|
||||
|
||||
## Movement provider order
|
||||
@export var order : int = 10
|
||||
|
||||
## Movement speed
|
||||
@export var max_speed : float = 3.0
|
||||
|
||||
## If true, the player can strafe
|
||||
@export var strafe : bool = false
|
||||
|
||||
## Input action for movement direction
|
||||
@export var input_forward : String = "ui_up"
|
||||
@export var input_backward : String = "ui_down"
|
||||
@export var input_left : String = "ui_left"
|
||||
@export var input_right : String = "ui_right"
|
||||
|
||||
|
||||
# XRStart node
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
|
||||
|
||||
# Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsDesktopMovementDirect" or super(xr_name)
|
||||
|
||||
|
||||
# Perform jump movement
|
||||
func physics_movement(_delta: float, player_body: XRToolsPlayerBody, _disabled: bool):
|
||||
# Skip if the controller isn't active
|
||||
if !player_body.enabled or xr_start_node.is_xr_active():
|
||||
return
|
||||
|
||||
#Calculate input vector
|
||||
var input_dir = Input.get_vector(input_left, input_right, input_backward, input_forward)
|
||||
|
||||
# Apply forwards/backwards ground control
|
||||
player_body.ground_control_velocity.y += input_dir.y * max_speed
|
||||
|
||||
# Apply left/right ground control
|
||||
if strafe:
|
||||
player_body.ground_control_velocity.x += input_dir.x * max_speed
|
||||
|
||||
# Clamp ground control
|
||||
var length := player_body.ground_control_velocity.length()
|
||||
if length > max_speed:
|
||||
player_body.ground_control_velocity *= max_speed / length
|
||||
|
||||
## Find the right [XRToolsDesktopMovementDirect] node.
|
||||
##
|
||||
## This function searches from the specified node for the right controller
|
||||
## [XRToolsDesktopMovementDirect] assuming the node is a sibling of the [XROrigin3D].
|
||||
static func find(node : Node) -> XRToolsDesktopMovementDirect:
|
||||
return XRTools.find_xr_child(
|
||||
XRHelpers.get_xr_origin(node),
|
||||
"*",
|
||||
"XRToolsDesktopMovementDirect") as XRToolsDesktopMovementDirect
|
||||
@@ -0,0 +1 @@
|
||||
uid://ciqexxqb7lxs4
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://6uusxts6n6gm"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ciqexxqb7lxs4" path="res://addons/godot-xr-tools/desktop-support/movement_desktop_direct.gd" id="1_e8v0q"]
|
||||
|
||||
[node name="MovementDesktopDirect" type="Node3D" groups=["movement_providers"]]
|
||||
script = ExtResource("1_e8v0q")
|
||||
182
addons/godot-xr-tools/desktop-support/movement_desktop_flight.gd
Normal file
182
addons/godot-xr-tools/desktop-support/movement_desktop_flight.gd
Normal file
@@ -0,0 +1,182 @@
|
||||
@tool
|
||||
class_name XRToolsDesktopMovementFlight
|
||||
extends XRToolsMovementProvider
|
||||
|
||||
|
||||
## XR Tools 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.
|
||||
##
|
||||
## 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 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.
|
||||
|
||||
|
||||
## Signal emitted when flight starts
|
||||
signal flight_started()
|
||||
|
||||
## Signal emitted when flight finishes
|
||||
signal flight_finished()
|
||||
|
||||
|
||||
## Movement provider order
|
||||
@export var order : int = 30
|
||||
|
||||
|
||||
## Flight toggle button
|
||||
@export var flight_button : String = "ui_focus_next"
|
||||
@export var input_forward : String = "ui_up"
|
||||
@export var input_backward : String = "ui_down"
|
||||
@export var input_left : String = "ui_left"
|
||||
@export var input_right : String = "ui_right"
|
||||
|
||||
## Flight speed from control
|
||||
@export var speed_scale : float = 5.0
|
||||
|
||||
## Flight traction pulling flight velocity towards the controlled speed
|
||||
@export var speed_traction : float = 3.0
|
||||
|
||||
## Flight acceleration from control
|
||||
@export var acceleration_scale : float = 0.0
|
||||
|
||||
## Flight drag
|
||||
@export var drag : float = 0.1
|
||||
|
||||
## Guidance effect (virtual fins/wings)
|
||||
@export var guidance : float = 0.0
|
||||
|
||||
## If true, flight movement is exclusive preventing further movement functions
|
||||
@export var exclusive : bool = true
|
||||
|
||||
|
||||
## Flight button state
|
||||
var _flight_button : bool = false
|
||||
|
||||
|
||||
# Node references
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
@onready var _camera := XRHelpers.get_xr_camera(self)
|
||||
|
||||
|
||||
# Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsDesktopMovementFlight" or super(xr_name)
|
||||
|
||||
|
||||
func _ready():
|
||||
# In Godot 4 we must now manually call our super class ready function
|
||||
super()
|
||||
|
||||
|
||||
# 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 !player_body.enabled or xr_start_node.is_xr_active():
|
||||
set_flying(false)
|
||||
return
|
||||
|
||||
# Detect press of flight button
|
||||
var old_flight_button = _flight_button
|
||||
_flight_button = Input.is_action_pressed(flight_button)
|
||||
if _flight_button and !old_flight_button:
|
||||
set_flying(!is_active)
|
||||
|
||||
# Skip if not flying
|
||||
if !is_active:
|
||||
return
|
||||
|
||||
# Select the pitch vector
|
||||
var pitch_vector: Vector3
|
||||
# Use the vertical part of the 'head' forwards vector
|
||||
pitch_vector = -_camera.transform.basis.z.y * player_body.up_player
|
||||
|
||||
# Select the bearing vector
|
||||
var bearing_vector: Vector3
|
||||
# Use the horizontal part of the 'head' forwards vector
|
||||
bearing_vector = -_camera.global_transform.basis.z \
|
||||
.slide(player_body.up_player)
|
||||
|
||||
# Construct the flight bearing
|
||||
var forwards := (bearing_vector.normalized() + pitch_vector).normalized()
|
||||
var side := forwards.cross(player_body.up_player)
|
||||
|
||||
# Construct the target velocity
|
||||
var input_dir = Input.get_vector(input_left, input_right, input_backward, input_forward)
|
||||
var joy_forwards :float= input_dir.y
|
||||
var joy_side :float= input_dir.x
|
||||
var heading := forwards * joy_forwards + side * joy_side
|
||||
|
||||
# Calculate the flight velocity
|
||||
var flight_velocity := player_body.velocity
|
||||
flight_velocity *= 1.0 - drag * delta
|
||||
flight_velocity = flight_velocity.lerp(heading * speed_scale, speed_traction * delta)
|
||||
flight_velocity += heading * acceleration_scale * delta
|
||||
|
||||
# Apply virtual guidance effect
|
||||
if guidance > 0.0:
|
||||
var velocity_forwards := forwards * flight_velocity.length()
|
||||
flight_velocity = flight_velocity.lerp(velocity_forwards, guidance * delta)
|
||||
|
||||
# If exclusive then perform the exclusive move-and-slide
|
||||
if exclusive:
|
||||
player_body.velocity = player_body.move_player(flight_velocity)
|
||||
return true
|
||||
|
||||
# Update velocity and return for additional effects
|
||||
player_body.velocity = flight_velocity
|
||||
return
|
||||
|
||||
|
||||
func set_flying(active: bool) -> void:
|
||||
# Skip if no change
|
||||
if active == is_active:
|
||||
return
|
||||
|
||||
# Update state
|
||||
is_active = active
|
||||
|
||||
# Handle state change
|
||||
if is_active:
|
||||
emit_signal("flight_started")
|
||||
else:
|
||||
emit_signal("flight_finished")
|
||||
|
||||
|
||||
# This method verifies the movement provider has a valid configuration.
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var warnings := super()
|
||||
|
||||
# Verify the camera
|
||||
if !XRHelpers.get_xr_camera(self):
|
||||
warnings.append("Unable to find XRCamera3D")
|
||||
|
||||
# Verify the left controller
|
||||
if !XRHelpers.get_left_controller(self):
|
||||
warnings.append("Unable to find left XRController3D node")
|
||||
|
||||
# Verify the right controller
|
||||
if !XRHelpers.get_right_controller(self):
|
||||
warnings.append("Unable to find left XRController3D node")
|
||||
|
||||
# Return warnings
|
||||
return warnings
|
||||
@@ -0,0 +1 @@
|
||||
uid://te6vlh1cbi7o
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://cfa5gsol863rv"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://te6vlh1cbi7o" path="res://addons/godot-xr-tools/desktop-support/movement_desktop_flight.gd" id="1_exmlf"]
|
||||
|
||||
[node name="MovementDesktopFlight" type="Node3D" groups=["movement_providers"]]
|
||||
script = ExtResource("1_exmlf")
|
||||
@@ -0,0 +1,43 @@
|
||||
@tool
|
||||
class_name XRToolsDesktopMovementJump
|
||||
extends XRToolsMovementProvider
|
||||
|
||||
|
||||
## XR Tools Movement Provider for Jumping
|
||||
##
|
||||
## This script provides jumping mechanics for the player. This script works
|
||||
## with the [XRToolsPlayerBody] attached to the players [XROrigin3D].
|
||||
##
|
||||
## The player enables jumping by attaching an [XRToolsMovementJump] as a
|
||||
## child of the appropriate [XRController3D], then configuring the jump button
|
||||
## and jump velocity.
|
||||
|
||||
|
||||
## Movement provider order
|
||||
@export var order : int = 20
|
||||
|
||||
## Button to trigger jump
|
||||
@export var jump_button_action : String = "ui_accept"
|
||||
|
||||
|
||||
# Node references
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
|
||||
|
||||
# Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsDesktopMovementJump" or super(xr_name)
|
||||
|
||||
|
||||
# Perform jump movement
|
||||
func physics_movement(_delta: float, player_body: XRToolsPlayerBody, _disabled: bool):
|
||||
# Skip if the jump controller isn't active
|
||||
if !player_body.enabled or xr_start_node.is_xr_active():
|
||||
return
|
||||
|
||||
# Request jump if the button is pressed
|
||||
if Input.is_action_pressed(jump_button_action):
|
||||
player_body.request_jump()
|
||||
@@ -0,0 +1 @@
|
||||
uid://b0l4n05yrf11b
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dluln6777mmh3"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://b0l4n05yrf11b" path="res://addons/godot-xr-tools/desktop-support/movement_desktop_jump.gd" id="1_tccpc"]
|
||||
|
||||
[node name="MovementDesktopJump" type="Node3D" groups=["movement_providers"]]
|
||||
script = ExtResource("1_tccpc")
|
||||
144
addons/godot-xr-tools/desktop-support/movement_desktop_sprint.gd
Normal file
144
addons/godot-xr-tools/desktop-support/movement_desktop_sprint.gd
Normal file
@@ -0,0 +1,144 @@
|
||||
@tool
|
||||
class_name XRToolsDesktopMovementSprint
|
||||
extends XRToolsMovementProvider
|
||||
|
||||
|
||||
## XR Tools Movement Provider for Sprinting
|
||||
##
|
||||
## This script provides sprinting movement for the player. It assumes there is
|
||||
## a direct movement node in the scene otherwise it will not be functional.
|
||||
##
|
||||
## There will not be an error, there just will not be any reason for it to
|
||||
## have any impact on the player. This node should be a direct child of
|
||||
## the [XROrigin3D] node rather than to a specific [XRController3D].
|
||||
|
||||
|
||||
## Signal emitted when sprinting starts
|
||||
signal sprinting_started()
|
||||
|
||||
## Signal emitted when sprinting finishes
|
||||
signal sprinting_finished()
|
||||
|
||||
|
||||
## Enumeration of sprinting modes - toggle or hold button
|
||||
enum SprintType {
|
||||
HOLD_TO_SPRINT, ## Hold button to sprint
|
||||
TOGGLE_SPRINT, ## Toggle sprinting on button press
|
||||
}
|
||||
|
||||
|
||||
## Type of sprinting
|
||||
@export var sprint_type : SprintType = SprintType.HOLD_TO_SPRINT
|
||||
|
||||
## Sprint speed multiplier (multiplier from speed set by direct movement node(s))
|
||||
@export_range(1.0, 4.0) var sprint_speed_multiplier : float = 2.0
|
||||
|
||||
## Movement provider order
|
||||
@export var order : int = 11
|
||||
|
||||
## Sprint button
|
||||
@export var sprint_button : String = "action_sprint"
|
||||
|
||||
# Sprint button down state
|
||||
var _sprint_button_down : bool = false
|
||||
|
||||
# Variable to hold left controller direct movement node original max speed
|
||||
var _direct_original_max_speed : float = 0.0
|
||||
|
||||
|
||||
# XRStart node
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
|
||||
|
||||
# Variable used to cache left controller direct movement function, if any
|
||||
@onready var _desktop_direct_move := XRToolsDesktopMovementDirect.find(self)
|
||||
|
||||
|
||||
|
||||
|
||||
# Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsDesktopMovementSprint" or super(xr_name)
|
||||
|
||||
|
||||
func _ready():
|
||||
# In Godot 4 we must now manually call our super class ready function
|
||||
super()
|
||||
|
||||
|
||||
# Perform sprinting
|
||||
func physics_movement(_delta: float, player_body: XRToolsPlayerBody, disabled: bool):
|
||||
# Skip if the controller isn't active or is not enabled
|
||||
if !player_body.enabled or xr_start_node.is_xr_active() or disabled == true or !enabled:
|
||||
set_sprinting(false)
|
||||
return
|
||||
|
||||
# Detect sprint button down and pressed states
|
||||
var sprint_button_down := Input.is_action_pressed(sprint_button)
|
||||
var sprint_button_pressed := sprint_button_down and !_sprint_button_down
|
||||
_sprint_button_down = sprint_button_down
|
||||
|
||||
# Calculate new sprinting state
|
||||
var sprinting := is_active
|
||||
match sprint_type:
|
||||
SprintType.HOLD_TO_SPRINT:
|
||||
# Sprint when button down
|
||||
sprinting = sprint_button_down
|
||||
|
||||
SprintType.TOGGLE_SPRINT:
|
||||
# Toggle when button pressed
|
||||
if sprint_button_pressed:
|
||||
sprinting = !sprinting
|
||||
|
||||
# Update sprinting state
|
||||
if sprinting != is_active:
|
||||
set_sprinting(sprinting)
|
||||
|
||||
|
||||
# Public function used to set sprinting active or not active
|
||||
func set_sprinting(active: bool) -> void:
|
||||
# Skip if no change
|
||||
if active == is_active:
|
||||
return
|
||||
|
||||
# Update state
|
||||
is_active = active
|
||||
|
||||
# Handle state change
|
||||
if is_active:
|
||||
# We are sprinting
|
||||
emit_signal("sprinting_started")
|
||||
|
||||
# Since max speeds could be changed while game is running, check
|
||||
# now for original max speeds of left and right nodes
|
||||
if _desktop_direct_move:
|
||||
_direct_original_max_speed = _desktop_direct_move.max_speed
|
||||
|
||||
# Set both controllers' direct movement functions, if appliable, to
|
||||
# the sprinting speed
|
||||
if _desktop_direct_move:
|
||||
_desktop_direct_move.max_speed = \
|
||||
_direct_original_max_speed * sprint_speed_multiplier
|
||||
else:
|
||||
# We are not sprinting
|
||||
emit_signal("sprinting_finished")
|
||||
|
||||
# Set both controllers' direct movement functions, if applicable, to
|
||||
# their original speeds
|
||||
if _desktop_direct_move:
|
||||
_desktop_direct_move.max_speed = _direct_original_max_speed
|
||||
|
||||
|
||||
# This method verifies the movement provider has a valid configuration.
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var warnings := super()
|
||||
|
||||
# Make sure player has at least one direct movement node
|
||||
if !XRToolsDesktopMovementDirect.find(self):
|
||||
warnings.append("Player missing XRToolsDesktopMovementDirect node")
|
||||
|
||||
# Return warnings
|
||||
return warnings
|
||||
@@ -0,0 +1 @@
|
||||
uid://dskqlyywoylkm
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dgm5op1hausw5"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dskqlyywoylkm" path="res://addons/godot-xr-tools/desktop-support/movement_desktop_sprint.gd" id="1_md0f7"]
|
||||
|
||||
[node name="MovementDesktopSprint" type="Node3D" groups=["movement_providers"]]
|
||||
script = ExtResource("1_md0f7")
|
||||
133
addons/godot-xr-tools/desktop-support/movement_desktop_turn.gd
Normal file
133
addons/godot-xr-tools/desktop-support/movement_desktop_turn.gd
Normal file
@@ -0,0 +1,133 @@
|
||||
@tool
|
||||
class_name XRToolsDesktopMovementTurn
|
||||
extends XRToolsMovementProvider
|
||||
|
||||
|
||||
## XR Tools Movement Provider for Turning
|
||||
##
|
||||
## This script provides turning support for the player. This script works
|
||||
## with the PlayerBody attached to the players XROrigin3D.
|
||||
|
||||
|
||||
## Movement mode
|
||||
enum TurnMode {
|
||||
DEFAULT, ## Use turn mode from project/user settings
|
||||
SNAP, ## Use snap-turning
|
||||
SMOOTH ## Use smooth-turning
|
||||
}
|
||||
|
||||
|
||||
## Movement provider order
|
||||
@export var order : int = 6
|
||||
|
||||
## Movement mode property
|
||||
@export var turn_mode : TurnMode = TurnMode.SMOOTH
|
||||
|
||||
## Smooth turn speed in radians per second
|
||||
@export var smooth_turn_speed : float = 2.0
|
||||
|
||||
## Seconds per step (at maximum turn rate)
|
||||
@export var step_turn_delay : float = 0.2
|
||||
|
||||
## Step turn angle in degrees
|
||||
@export var step_turn_angle : float = 20.0
|
||||
|
||||
## Our directional input
|
||||
@export var input_action : String = "primary"
|
||||
|
||||
## Our directional input
|
||||
@export var clear_mouse_move_when_body_not_active : bool = true
|
||||
@export var clear_cam_x_when_body_not_active : bool = false
|
||||
|
||||
|
||||
@export var invert_y : bool = true
|
||||
|
||||
var plr_body : XRToolsPlayerBody
|
||||
var mouse_move_vector := Vector2.ZERO
|
||||
var _last_plr_bd_status := true
|
||||
|
||||
# Turn step accumulator
|
||||
var _turn_step : float = 0.0
|
||||
|
||||
|
||||
|
||||
# XRStart node
|
||||
@onready var xr_start_node = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,
|
||||
"*Staging",
|
||||
"XRToolsStaging"),"StartXR","Node")
|
||||
|
||||
|
||||
# Add support for is_xr_class on XRTools classes
|
||||
func is_xr_class(xr_name: String) -> bool:
|
||||
return xr_name == "XRToolsDesktopMovementTurn" or super(xr_name)
|
||||
|
||||
func _unhandled_input(event):
|
||||
if !enabled:
|
||||
return
|
||||
if event is InputEventMouseMotion:
|
||||
event.relative*=.1
|
||||
if invert_y:
|
||||
event.relative.y *= -1
|
||||
mouse_move_vector += event.relative
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if is_instance_valid(plr_body):
|
||||
if !plr_body.enabled and !xr_start_node.is_xr_active() and _last_plr_bd_status!=plr_body.enabled:
|
||||
if clear_mouse_move_when_body_not_active:
|
||||
mouse_move_vector=Vector2.ZERO
|
||||
if clear_cam_x_when_body_not_active:
|
||||
plr_body.camera_node.rotation_degrees.x=0
|
||||
_last_plr_bd_status=!plr_body.enabled
|
||||
elif plr_body.enabled:
|
||||
_last_plr_bd_status=!plr_body.enabled
|
||||
|
||||
|
||||
# Perform jump movement
|
||||
func physics_movement(delta: float, player_body: XRToolsPlayerBody, _disabled: bool):
|
||||
# Skip if the player body isn't active
|
||||
plr_body=player_body
|
||||
if !player_body.enabled or xr_start_node.is_xr_active():
|
||||
if clear_mouse_move_when_body_not_active:
|
||||
mouse_move_vector=Vector2.ZERO
|
||||
#if clear_cam_x_when_body_not_active:
|
||||
# player_body.camera_node.rotation_degrees.x=0
|
||||
return
|
||||
|
||||
var deadzone = 0.1
|
||||
# if _snap_turning():
|
||||
# deadzone = XRTools.get_snap_turning_deadzone()
|
||||
|
||||
# Read the left/right joystick axis
|
||||
var left_right := mouse_move_vector.x
|
||||
#if abs(left_right) <= deadzone:
|
||||
# # Not turning
|
||||
# _turn_step = 0.0
|
||||
# return
|
||||
|
||||
# Handle smooth rotation
|
||||
#if !_snap_turning():
|
||||
left_right -= deadzone * sign(left_right)
|
||||
player_body.rotate_player(smooth_turn_speed * delta * left_right)
|
||||
player_body.camera_node.rotation_degrees.x=clamp(
|
||||
player_body.camera_node.rotation_degrees.x+smooth_turn_speed * mouse_move_vector.y,
|
||||
-89.999,
|
||||
89.999)
|
||||
mouse_move_vector=Vector2.ZERO
|
||||
return
|
||||
|
||||
|
||||
|
||||
# Test if snap turning should be used
|
||||
func _snap_turning():
|
||||
#temp removal - IDK if normal controller will be considered to have this as use
|
||||
return false
|
||||
# match turn_mode:
|
||||
# TurnMode.SNAP:
|
||||
# return true
|
||||
#
|
||||
# TurnMode.SMOOTH:
|
||||
# return false
|
||||
#
|
||||
# _:
|
||||
# return XRToolsUserSettings.snap_turning
|
||||
@@ -0,0 +1 @@
|
||||
uid://bjqk58f7j3hgl
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://c4d13r420hnx2"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bjqk58f7j3hgl" path="res://addons/godot-xr-tools/desktop-support/movement_desktop_turn.gd" id="1_qv43c"]
|
||||
|
||||
[node name="MovementDesktopTurn" type="Node3D" groups=["movement_providers"]]
|
||||
script = ExtResource("1_qv43c")
|
||||
@@ -0,0 +1,62 @@
|
||||
@tool
|
||||
class_name XRToolsMovementGravityZones
|
||||
extends XRToolsMovementProvider
|
||||
|
||||
|
||||
# Default wall-walk mask of 4:wall-walk
|
||||
const DEFAULT_MASK := 0b0000_0000_0000_0000_0000_0000_0000_1000
|
||||
|
||||
|
||||
## Wall walking provider order
|
||||
@export var order : int = 26
|
||||
|
||||
## Set our follow layer mask
|
||||
@export_flags_3d_physics var follow_mask : int = DEFAULT_MASK
|
||||
|
||||
var _gravity_dir := Vector3(0,-9.8,0)
|
||||
|
||||
@onready var fly_desktop : XRToolsDesktopMovementFlight = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,"*","XROrigin3D"),
|
||||
"*",
|
||||
"XRToolsDesktopMovementFlight")
|
||||
|
||||
@onready var fly_xr : XRToolsMovementFlight = XRTools.find_xr_child(
|
||||
XRTools.find_xr_ancestor(self,"*","XROrigin3D"),
|
||||
"*",
|
||||
"XRToolsMovementFlight")
|
||||
|
||||
|
||||
func physics_pre_movement(_delta: float, player_body: XRToolsPlayerBody):
|
||||
# Test for collision with wall under feet
|
||||
var gravity_zones1 = get_tree().get_nodes_in_group("gravity_zone1")
|
||||
var gravity_zones2 = get_tree().get_nodes_in_group("gravity_zone2")
|
||||
var gravity_zones3 = get_tree().get_nodes_in_group("gravity_zone3")
|
||||
|
||||
#_gravity_dir = Vector3(0,-9.8,0)
|
||||
var grav_z := 0
|
||||
for zone in gravity_zones3:
|
||||
if zone.overlaps_body(player_body) and zone is Area3D:
|
||||
grav_z=3
|
||||
_gravity_dir=zone.global_transform.basis.y*zone.gravity*-1
|
||||
|
||||
if grav_z==0:
|
||||
for zone in gravity_zones2:
|
||||
if zone.overlaps_body(player_body) and zone is Area3D:
|
||||
grav_z=2
|
||||
_gravity_dir=zone.global_transform.basis.y*zone.gravity*-1
|
||||
|
||||
if grav_z==0:
|
||||
for zone in gravity_zones1:
|
||||
if zone.overlaps_body(player_body) and zone is Area3D:
|
||||
grav_z=1
|
||||
_gravity_dir=zone.global_transform.basis.y*zone.gravity*-1
|
||||
|
||||
if grav_z==0:
|
||||
fly_desktop.set_flying(true)
|
||||
fly_xr.set_flying(true)
|
||||
else:
|
||||
fly_desktop.set_flying(false)
|
||||
fly_xr.set_flying(false)
|
||||
|
||||
# Modify the player gravity
|
||||
player_body.gravity = _gravity_dir
|
||||
@@ -0,0 +1 @@
|
||||
uid://dyifp672tjli7
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://kx0gpdwdcham"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dyifp672tjli7" path="res://addons/godot-xr-tools/desktop-support/movement_gravity_zones.gd" id="1"]
|
||||
|
||||
[node name="MovementGravityZones" type="Node3D" groups=["movement_providers"]]
|
||||
script = ExtResource("1")
|
||||
Reference in New Issue
Block a user