mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2025-12-16 13:30:07 +01:00
Use static typing in all demos (#1063)
This leads to code that is easier to understand and runs faster thanks to GDScript's typed instructions. The untyped declaration warning is now enabled on all projects where type hints were added. All projects currently run without any untyped declration warnings. Dodge the Creeps and Squash the Creeps demos intentionally don't use type hints to match the documentation, where type hints haven't been adopted yet (given its beginner focus).
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
@tool
|
||||
extends Node3D
|
||||
|
||||
@export_range(0, 1, 0.1) var fade = 0.0:
|
||||
@export_range(0, 1, 0.1) var fade := 0.0:
|
||||
set(value):
|
||||
fade = value
|
||||
if is_inside_tree():
|
||||
_update_fade()
|
||||
|
||||
var material : ShaderMaterial
|
||||
var material: ShaderMaterial
|
||||
|
||||
func _update_fade():
|
||||
|
||||
func _update_fade() -> void:
|
||||
if fade == 0.0:
|
||||
$MeshInstance3D.visible = false
|
||||
else:
|
||||
@@ -17,7 +18,7 @@ func _update_fade():
|
||||
material.set_shader_parameter("albedo", Color(0.0, 0.0, 0.0, fade))
|
||||
$MeshInstance3D.visible = true
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
|
||||
func _ready() -> void:
|
||||
material = $MeshInstance3D.material_override
|
||||
_update_fade()
|
||||
|
||||
@@ -1,75 +1,77 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
# Settings to control the character
|
||||
@export var rotation_speed : float = 1.0
|
||||
@export var movement_speed : float = 5.0
|
||||
@export var movement_acceleration : float = 5.0
|
||||
# Settings to control the character.
|
||||
@export var rotation_speed := 1.0
|
||||
@export var movement_speed := 5.0
|
||||
@export var movement_acceleration := 5.0
|
||||
|
||||
# Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
var gravity := float(ProjectSettings.get_setting("physics/3d/default_gravity"))
|
||||
|
||||
# Helper variables to keep our code readable
|
||||
@onready var origin_node : XROrigin3D = $XROrigin3D
|
||||
@onready var camera_node : XRCamera3D = $XROrigin3D/XRCamera3D
|
||||
@onready var neck_position_node : Node3D = $XROrigin3D/XRCamera3D/Neck
|
||||
@onready var black_out : Node3D = $XROrigin3D/XRCamera3D/BlackOut
|
||||
# Helper variables to keep our code readable.
|
||||
@onready var origin_node: XROrigin3D = $XROrigin3D
|
||||
@onready var camera_node: XRCamera3D = $XROrigin3D/XRCamera3D
|
||||
@onready var neck_position_node: Node3D = $XROrigin3D/XRCamera3D/Neck
|
||||
@onready var black_out: Node3D = $XROrigin3D/XRCamera3D/BlackOut
|
||||
|
||||
# `recenter` is called when the user has requested their view to be recentered.
|
||||
# The code here assumes the player has walked into an area they shouldn't be
|
||||
# and we return the player back to the character body.
|
||||
# But other strategies can be applied here as well such as returning the player
|
||||
# to a starting position or a checkpoint.
|
||||
func recenter():
|
||||
# Calculate where our camera should be, we start with our global transform
|
||||
## Called when the user has requested their view to be recentered.
|
||||
func recenter() -> void:
|
||||
# The code here assumes the player has walked into an area they shouldn't be
|
||||
# and we return the player back to the character body.
|
||||
# But other strategies can be applied here as well such as returning the player
|
||||
# to a starting position or a checkpoint.
|
||||
|
||||
# Calculate where our camera should be, we start with our global transform.
|
||||
var new_camera_transform : Transform3D = global_transform
|
||||
|
||||
# Set to the height of our neck joint
|
||||
# Set to the height of our neck joint.
|
||||
new_camera_transform.origin.y = neck_position_node.global_position.y
|
||||
|
||||
# Apply transform our our next position to get our desired camera transform
|
||||
# Apply transform our our next position to get our desired camera transform.
|
||||
new_camera_transform = new_camera_transform * neck_position_node.transform.inverse()
|
||||
|
||||
# Remove tilt from camera transform
|
||||
# Remove tilt from camera transform.
|
||||
var camera_transform : Transform3D = camera_node.transform
|
||||
var forward_dir : Vector3 = camera_transform.basis.z
|
||||
forward_dir.y = 0.0
|
||||
camera_transform = camera_transform.looking_at(camera_transform.origin + forward_dir.normalized(), Vector3.UP, true)
|
||||
|
||||
# Update our XR location
|
||||
# Update our XR location.
|
||||
origin_node.global_transform = new_camera_transform * camera_transform.inverse()
|
||||
|
||||
# `_get_movement_input` returns our move input by querying the move action on each controller
|
||||
|
||||
# Returns our move input by querying the move action on each controller.
|
||||
func _get_movement_input() -> Vector2:
|
||||
var movement : Vector2 = Vector2()
|
||||
var movement := Vector2()
|
||||
|
||||
# If move is not bound to one of our controllers,
|
||||
# that controller will return a Vector2(0.0, 0.0)
|
||||
# that controller will return `Vector2.ZERO`.
|
||||
movement += $XROrigin3D/LeftHand.get_vector2("move")
|
||||
movement += $XROrigin3D/RightHand.get_vector2("move")
|
||||
|
||||
return movement
|
||||
|
||||
# `_process_on_physical_movement` handles the physical movement of the player
|
||||
# `_process_on_physical_movement()` handles the physical movement of the player
|
||||
# adjusting our character body position to "catch up to" the player.
|
||||
# If the character body encounters an obstruction our view will black out
|
||||
# and we will stop further character movement until the player physically
|
||||
# moves back.
|
||||
func _process_on_physical_movement(delta) -> bool:
|
||||
# Remember our current velocity, we'll apply that later
|
||||
var current_velocity = velocity
|
||||
func _process_on_physical_movement(delta: float) -> bool:
|
||||
# Remember our current velocity, as we'll apply that later.
|
||||
var current_velocity := velocity
|
||||
|
||||
# Start by rotating the player to face the same way our real player is
|
||||
# Start by rotating the player to face the same way our real player is.
|
||||
var camera_basis: Basis = origin_node.transform.basis * camera_node.transform.basis
|
||||
var forward: Vector2 = Vector2(camera_basis.z.x, camera_basis.z.z)
|
||||
var angle: float = forward.angle_to(Vector2(0.0, 1.0))
|
||||
|
||||
# Rotate our character body
|
||||
# Rotate our character body.
|
||||
transform.basis = transform.basis.rotated(Vector3.UP, angle)
|
||||
|
||||
# Reverse this rotation our origin node
|
||||
# Reverse this rotation our origin node.
|
||||
origin_node.transform = Transform3D().rotated(Vector3.UP, -angle) * origin_node.transform
|
||||
|
||||
# Now apply movement, first move our player body to the right location
|
||||
# Now apply movement, first move our player body to the right location.
|
||||
var org_player_body: Vector3 = global_transform.origin
|
||||
var player_body_location: Vector3 = origin_node.transform * camera_node.transform * neck_position_node.transform.origin
|
||||
player_body_location.y = 0.0
|
||||
@@ -78,34 +80,33 @@ func _process_on_physical_movement(delta) -> bool:
|
||||
velocity = (player_body_location - org_player_body) / delta
|
||||
move_and_slide()
|
||||
|
||||
# Now move our XROrigin back
|
||||
var delta_movement = global_transform.origin - org_player_body
|
||||
# Now move our XROrigin back.
|
||||
var delta_movement := global_transform.origin - org_player_body
|
||||
origin_node.global_transform.origin -= delta_movement
|
||||
|
||||
# Negate any height change in local space due to player hitting ramps etc.
|
||||
# Negate any height change in local space due to player hitting ramps, etc.
|
||||
origin_node.transform.origin.y = 0.0
|
||||
|
||||
# Return our value
|
||||
# Return our value.
|
||||
velocity = current_velocity
|
||||
|
||||
# Check if we managed to move where we wanted to
|
||||
var location_offset = (player_body_location - global_transform.origin).length()
|
||||
# Check if we managed to move where we wanted to.
|
||||
var location_offset := (player_body_location - global_transform.origin).length()
|
||||
if location_offset > 0.1:
|
||||
# We couldn't go where we wanted to, black out our screen
|
||||
black_out.fade = clamp((location_offset - 0.1) / 0.1, 0.0, 1.0)
|
||||
|
||||
# We couldn't go where we wanted to, black out our screen.
|
||||
black_out.fade = clampf((location_offset - 0.1) / 0.1, 0.0, 1.0)
|
||||
return true
|
||||
else:
|
||||
black_out.fade = 0.0
|
||||
return false
|
||||
|
||||
# `_process_movement_on_input` handles movement through controller input.
|
||||
# `_process_movement_on_input()` handles movement through controller input.
|
||||
# We first handle rotating the player and then apply movement.
|
||||
# We also apply the effects of gravity at this point.
|
||||
func _process_movement_on_input(is_colliding, delta):
|
||||
if !is_colliding:
|
||||
func _process_movement_on_input(is_colliding: bool, delta: float) -> void:
|
||||
if not is_colliding:
|
||||
# Only handle input if we've not physically moved somewhere we shouldn't.
|
||||
var movement_input = _get_movement_input()
|
||||
var movement_input := _get_movement_input()
|
||||
|
||||
# First handle rotation, to keep this example simple we are implementing
|
||||
# "smooth" rotation here. This can lead to motion sickness.
|
||||
@@ -117,7 +118,7 @@ func _process_movement_on_input(is_colliding, delta):
|
||||
# Straffing can be added by using the movement_input.x input
|
||||
# and using a different input for rotational control.
|
||||
# Straffing is more prone to motion sickness.
|
||||
var direction = global_transform.basis * Vector3(0.0, 0.0, -movement_input.y) * movement_speed
|
||||
var direction := global_transform.basis * Vector3(0.0, 0.0, -movement_input.y) * movement_speed
|
||||
if direction:
|
||||
velocity.x = move_toward(velocity.x, direction.x, delta * movement_acceleration)
|
||||
velocity.z = move_toward(velocity.z, direction.z, delta * movement_acceleration)
|
||||
@@ -130,7 +131,7 @@ func _process_movement_on_input(is_colliding, delta):
|
||||
|
||||
move_and_slide()
|
||||
|
||||
# _physics_process handles our player movement.
|
||||
func _physics_process(delta):
|
||||
var is_colliding = _process_on_physical_movement(delta)
|
||||
# `_physics_process()` handles our player movement.
|
||||
func _physics_process(delta: float) -> void:
|
||||
var is_colliding := _process_on_physical_movement(delta)
|
||||
_process_movement_on_input(is_colliding, delta)
|
||||
|
||||
@@ -11,10 +11,14 @@ config_version=5
|
||||
[application]
|
||||
|
||||
config/name="OpenXR Character Centric Movement"
|
||||
config/tags=PackedStringArray("demo", "official", "xr")
|
||||
run/main_scene="res://main.tscn"
|
||||
config/features=PackedStringArray("4.2", "GL Compatibility")
|
||||
config/icon="res://icon.svg"
|
||||
config/tags=PackedStringArray("demo", "official", "xr")
|
||||
|
||||
[debug]
|
||||
|
||||
gdscript/warnings/untyped_declaration=1
|
||||
|
||||
[rendering]
|
||||
|
||||
|
||||
@@ -7,29 +7,28 @@ signal pose_recentered
|
||||
@export var maximum_refresh_rate : int = 90
|
||||
|
||||
var xr_interface : OpenXRInterface
|
||||
var xr_is_focussed = false
|
||||
var xr_is_focused := false
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
func _ready() -> void:
|
||||
xr_interface = XRServer.find_interface("OpenXR")
|
||||
if xr_interface and xr_interface.is_initialized():
|
||||
print("OpenXR instantiated successfully.")
|
||||
var vp : Viewport = get_viewport()
|
||||
|
||||
# Enable XR on our viewport
|
||||
# Enable XR on our viewport.
|
||||
vp.use_xr = true
|
||||
|
||||
# Make sure v-sync is off, v-sync is handled by OpenXR
|
||||
# Make sure V-Sync is off, as V-Sync is handled by OpenXR.
|
||||
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
|
||||
|
||||
# Enable VRS
|
||||
# Enable variable rate shading.
|
||||
if RenderingServer.get_rendering_device():
|
||||
vp.vrs_mode = Viewport.VRS_XR
|
||||
elif int(ProjectSettings.get_setting("xr/openxr/foveation_level")) == 0:
|
||||
push_warning("OpenXR: Recommend setting Foveation level to High in Project Settings")
|
||||
|
||||
# Connect the OpenXR events
|
||||
# Connect the OpenXR events.
|
||||
xr_interface.session_begun.connect(_on_openxr_session_begun)
|
||||
xr_interface.session_visible.connect(_on_openxr_visible_state)
|
||||
xr_interface.session_focussed.connect(_on_openxr_focused_state)
|
||||
@@ -41,22 +40,22 @@ func _ready():
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
# Handle OpenXR session ready
|
||||
# Handle OpenXR session ready.
|
||||
func _on_openxr_session_begun() -> void:
|
||||
# Get the reported refresh rate
|
||||
var current_refresh_rate = xr_interface.get_display_refresh_rate()
|
||||
# Get the reported refresh rate.
|
||||
var current_refresh_rate := xr_interface.get_display_refresh_rate()
|
||||
if current_refresh_rate > 0:
|
||||
print("OpenXR: Refresh rate reported as ", str(current_refresh_rate))
|
||||
else:
|
||||
print("OpenXR: No refresh rate given by XR runtime")
|
||||
|
||||
# See if we have a better refresh rate available
|
||||
var new_rate = current_refresh_rate
|
||||
var available_rates : Array = xr_interface.get_available_display_refresh_rates()
|
||||
if available_rates.size() == 0:
|
||||
# See if we have a better refresh rate available.
|
||||
var new_rate := current_refresh_rate
|
||||
var available_rates: Array[float] = xr_interface.get_available_display_refresh_rates()
|
||||
if available_rates.is_empty():
|
||||
print("OpenXR: Target does not support refresh rate extension")
|
||||
elif available_rates.size() == 1:
|
||||
# Only one available, so use it
|
||||
# Only one available, so use it.
|
||||
new_rate = available_rates[0]
|
||||
else:
|
||||
for rate in available_rates:
|
||||
@@ -69,20 +68,21 @@ func _on_openxr_session_begun() -> void:
|
||||
xr_interface.set_display_refresh_rate(new_rate)
|
||||
current_refresh_rate = new_rate
|
||||
|
||||
# Now match our physics rate
|
||||
Engine.physics_ticks_per_second = current_refresh_rate
|
||||
# Now match our physics rate. This is currently needed to avoid jittering,
|
||||
# due to physics interpolation not being used.
|
||||
Engine.physics_ticks_per_second = roundi(current_refresh_rate)
|
||||
|
||||
|
||||
# Handle OpenXR visible state
|
||||
# Handle OpenXR visible state.
|
||||
func _on_openxr_visible_state() -> void:
|
||||
# We always pass this state at startup,
|
||||
# but the second time we get this it means our player took off their headset
|
||||
if xr_is_focussed:
|
||||
# but the second time we get this, it means our player took off their headset.
|
||||
if xr_is_focused:
|
||||
print("OpenXR lost focus")
|
||||
|
||||
xr_is_focussed = false
|
||||
xr_is_focused = false
|
||||
|
||||
# pause our game
|
||||
# Pause our game.
|
||||
process_mode = Node.PROCESS_MODE_DISABLED
|
||||
|
||||
focus_lost.emit()
|
||||
@@ -91,19 +91,21 @@ func _on_openxr_visible_state() -> void:
|
||||
# Handle OpenXR focused state
|
||||
func _on_openxr_focused_state() -> void:
|
||||
print("OpenXR gained focus")
|
||||
xr_is_focussed = true
|
||||
xr_is_focused = true
|
||||
|
||||
# unpause our game
|
||||
# Unpause our game.
|
||||
process_mode = Node.PROCESS_MODE_INHERIT
|
||||
|
||||
focus_gained.emit()
|
||||
|
||||
# Handle OpenXR stopping state
|
||||
|
||||
# Handle OpenXR stopping state.
|
||||
func _on_openxr_stopping() -> void:
|
||||
# Our session is being stopped.
|
||||
print("OpenXR is stopping")
|
||||
|
||||
# Handle OpenXR pose recentered signal
|
||||
|
||||
# Handle OpenXR pose recentered signal.
|
||||
func _on_openxr_pose_recentered() -> void:
|
||||
# User recentered view, we have to react to this by recentering the view.
|
||||
# This is game implementation dependent.
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
@tool
|
||||
extends Node3D
|
||||
|
||||
@export_range(0, 1, 0.1) var fade = 0.0:
|
||||
@export_range(0, 1, 0.1) var fade := 0.0:
|
||||
set(value):
|
||||
fade = value
|
||||
if is_inside_tree():
|
||||
_update_fade()
|
||||
|
||||
var material : ShaderMaterial
|
||||
var material: ShaderMaterial
|
||||
|
||||
func _update_fade():
|
||||
func _update_fade() -> void:
|
||||
if fade == 0.0:
|
||||
$MeshInstance3D.visible = false
|
||||
else:
|
||||
@@ -17,7 +17,7 @@ func _update_fade():
|
||||
material.set_shader_parameter("albedo", Color(0.0, 0.0, 0.0, fade))
|
||||
$MeshInstance3D.visible = true
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
|
||||
func _ready() -> void:
|
||||
material = $MeshInstance3D.material_override
|
||||
_update_fade()
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
extends XROrigin3D
|
||||
|
||||
|
||||
# Settings to control the character
|
||||
@export var rotation_speed : float = 1.0
|
||||
@export var movement_speed : float = 5.0
|
||||
@export var movement_acceleration : float = 5.0
|
||||
# Settings to control the character.
|
||||
@export var rotation_speed := 1.0
|
||||
@export var movement_speed := 5.0
|
||||
@export var movement_acceleration := 5.0
|
||||
|
||||
# Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
var gravity := float(ProjectSettings.get_setting("physics/3d/default_gravity"))
|
||||
|
||||
# Helper variables to keep our code readable
|
||||
# Helper variables to keep our code readable.
|
||||
@onready var character_body : CharacterBody3D = $CharacterBody3D
|
||||
@onready var camera_node : XRCamera3D = $XRCamera3D
|
||||
@onready var neck_position_node : Node3D = $XRCamera3D/Neck
|
||||
@onready var black_out : Node3D = $XRCamera3D/BlackOut
|
||||
|
||||
# `recenter` is called when the user has requested their view to be recentered.
|
||||
# The code here assumes the player has walked into an area they shouldn't be
|
||||
# and we return the player back to the character body.
|
||||
# But other strategies can be applied here as well such as returning the player
|
||||
# to a starting position or a checkpoint.
|
||||
func recenter():
|
||||
# Calculate where our camera should be, we start with our global transform
|
||||
var new_camera_transform : Transform3D = character_body.global_transform
|
||||
## Called when the user has requested their view to be recentered.
|
||||
func recenter() -> void:
|
||||
# The code here assumes the player has walked into an area they shouldn't be
|
||||
# and we return the player back to the character body.
|
||||
# But other strategies can be applied here as well such as returning the player
|
||||
# to a starting position or a checkpoint.
|
||||
|
||||
# Set to the height of our neck joint
|
||||
# Calculate where our camera should be, we start with our global transform.
|
||||
var new_camera_transform: Transform3D = character_body.global_transform
|
||||
|
||||
# Set to the height of our neck joint.
|
||||
new_camera_transform.origin.y = neck_position_node.global_position.y
|
||||
|
||||
# Apply transform our our next position to get our desired camera transform
|
||||
# Apply transform our our next position to get our desired camera transform.
|
||||
new_camera_transform = new_camera_transform * neck_position_node.transform.inverse()
|
||||
|
||||
# Remove tilt from camera transform
|
||||
var camera_transform : Transform3D = camera_node.transform
|
||||
var forward_dir : Vector3 = camera_transform.basis.z
|
||||
# Remove tilt from camera transform.
|
||||
var camera_transform: Transform3D = camera_node.transform
|
||||
var forward_dir: Vector3 = camera_transform.basis.z
|
||||
forward_dir.y = 0.0
|
||||
camera_transform = camera_transform.looking_at(camera_transform.origin + forward_dir.normalized(), Vector3.UP, true)
|
||||
|
||||
# Update our XR location
|
||||
# Update our XR location.
|
||||
global_transform = new_camera_transform * camera_transform.inverse()
|
||||
|
||||
# Recenter character body
|
||||
# Recenter character body.
|
||||
character_body.transform = Transform3D()
|
||||
|
||||
# `_get_movement_input` returns our move input by querying the move action on each controller
|
||||
# `_get_movement_input()` returns our move input by querying the move action on each controller.
|
||||
func _get_movement_input() -> Vector2:
|
||||
var movement : Vector2 = Vector2()
|
||||
|
||||
# If move is not bound to one of our controllers,
|
||||
# that controller will return a Vector2(0.0, 0.0)
|
||||
# that controller will return `Vector2.ZERO`.
|
||||
movement += $LeftHand.get_vector2("move")
|
||||
movement += $RightHand.get_vector2("move")
|
||||
|
||||
@@ -58,33 +58,33 @@ func _get_movement_input() -> Vector2:
|
||||
# If the character body encounters an obstruction our view will black out
|
||||
# and we will stop further character movement until the player physically
|
||||
# moves back.
|
||||
func _process_on_physical_movement(delta) -> bool:
|
||||
# Remember our current velocity, we'll apply that later
|
||||
var current_velocity = character_body.velocity
|
||||
func _process_on_physical_movement(delta: float) -> bool:
|
||||
# Remember our current velocity, as we'll apply that later.
|
||||
var current_velocity := character_body.velocity
|
||||
|
||||
# Remember where our player body currently is
|
||||
# Remember where our player body currently is.
|
||||
var org_player_body: Vector3 = character_body.global_transform.origin
|
||||
|
||||
# Determine where our player body should be
|
||||
# Determine where our player body should be.
|
||||
var player_body_location: Vector3 = camera_node.transform * neck_position_node.transform.origin
|
||||
player_body_location.y = 0.0
|
||||
player_body_location = global_transform * player_body_location
|
||||
|
||||
# Attempt to move our character
|
||||
# Attempt to move our character.
|
||||
character_body.velocity = (player_body_location - org_player_body) / delta
|
||||
character_body.move_and_slide()
|
||||
|
||||
# Set back to our current value
|
||||
# Set back to our current value.
|
||||
character_body.velocity = current_velocity
|
||||
|
||||
# Check if we managed to move all the way, ignoring height change
|
||||
var movement_left = player_body_location - character_body.global_transform.origin
|
||||
# Check if we managed to move all the way, ignoring height change.
|
||||
var movement_left := player_body_location - character_body.global_transform.origin
|
||||
movement_left.y = 0.0
|
||||
|
||||
# Check if we managed to move where we wanted to
|
||||
var location_offset = movement_left.length()
|
||||
# Check if we managed to move where we wanted to.
|
||||
var location_offset := movement_left.length()
|
||||
if location_offset > 0.1:
|
||||
# We couldn't go where we wanted to, black out our screen
|
||||
# We couldn't go where we wanted to, black out our screen.
|
||||
black_out.fade = clamp((location_offset - 0.1) / 0.1, 0.0, 1.0)
|
||||
|
||||
return true
|
||||
@@ -92,23 +92,25 @@ func _process_on_physical_movement(delta) -> bool:
|
||||
black_out.fade = 0.0
|
||||
return false
|
||||
|
||||
func _copy_player_rotation_to_character_body():
|
||||
# We only copy our forward direction to our character body, we ignore tilt
|
||||
var camera_forward: Vector3 = -camera_node.global_transform.basis.z
|
||||
var body_forward: Vector3 = Vector3(camera_forward.x, 0.0, camera_forward.z)
|
||||
|
||||
func _copy_player_rotation_to_character_body() -> void:
|
||||
# We only copy our forward direction to our character body, we ignore tilt.
|
||||
var camera_forward := -camera_node.global_transform.basis.z
|
||||
var body_forward := Vector3(camera_forward.x, 0.0, camera_forward.z)
|
||||
|
||||
character_body.global_transform.basis = Basis.looking_at(body_forward, Vector3.UP)
|
||||
|
||||
|
||||
# `_process_movement_on_input` handles movement through controller input.
|
||||
# We first handle rotating the player and then apply movement.
|
||||
# We also apply the effects of gravity at this point.
|
||||
func _process_movement_on_input(is_colliding, delta):
|
||||
# Remember where our player body currently is
|
||||
func _process_movement_on_input(is_colliding: bool, delta: float) -> void:
|
||||
# Remember where our player body currently is.
|
||||
var org_player_body: Vector3 = character_body.global_transform.origin
|
||||
|
||||
if !is_colliding:
|
||||
if not is_colliding:
|
||||
# Only handle input if we've not physically moved somewhere we shouldn't.
|
||||
var movement_input = _get_movement_input()
|
||||
var movement_input := _get_movement_input()
|
||||
|
||||
# First handle rotation, to keep this example simple we are implementing
|
||||
# "smooth" rotation here. This can lead to motion sickness.
|
||||
@@ -119,15 +121,15 @@ func _process_movement_on_input(is_colliding, delta):
|
||||
var t2 := Transform3D()
|
||||
var rot := Transform3D()
|
||||
|
||||
# We are going to rotate the origin around the player
|
||||
var player_position = character_body.global_transform.origin - global_transform.origin
|
||||
# We are going to rotate the origin around the player.
|
||||
var player_position := character_body.global_transform.origin - global_transform.origin
|
||||
|
||||
t1.origin = -player_position
|
||||
t2.origin = player_position
|
||||
rot = rot.rotated(Vector3(0.0, 1.0, 0.0), -movement_input.x * delta * rotation_speed)
|
||||
global_transform = (global_transform * t2 * rot * t1).orthonormalized()
|
||||
|
||||
# Now ensure our player body is facing the correct way as well
|
||||
# Now ensure our player body is facing the correct way as well.
|
||||
_copy_player_rotation_to_character_body()
|
||||
|
||||
# Now handle forward/backwards movement.
|
||||
@@ -142,16 +144,17 @@ func _process_movement_on_input(is_colliding, delta):
|
||||
character_body.velocity.x = move_toward(character_body.velocity.x, 0, delta * movement_acceleration)
|
||||
character_body.velocity.z = move_toward(character_body.velocity.z, 0, delta * movement_acceleration)
|
||||
|
||||
# Always handle gravity
|
||||
# Always handle gravity.
|
||||
character_body.velocity.y -= gravity * delta
|
||||
|
||||
# Attempt to move our player
|
||||
# Attempt to move our player.
|
||||
character_body.move_and_slide()
|
||||
|
||||
# And now apply the actual movement to our origin
|
||||
# And now apply the actual movement to our origin.
|
||||
global_transform.origin += character_body.global_transform.origin - org_player_body
|
||||
|
||||
|
||||
# _physics_process handles our player movement.
|
||||
func _physics_process(delta):
|
||||
var is_colliding = _process_on_physical_movement(delta)
|
||||
func _physics_process(delta: float) -> void:
|
||||
var is_colliding := _process_on_physical_movement(delta)
|
||||
_process_movement_on_input(is_colliding, delta)
|
||||
|
||||
@@ -11,10 +11,14 @@ config_version=5
|
||||
[application]
|
||||
|
||||
config/name="OpenXR Origin Centric Movement"
|
||||
config/tags=PackedStringArray("demo", "official", "xr")
|
||||
run/main_scene="res://main.tscn"
|
||||
config/features=PackedStringArray("4.2", "GL Compatibility")
|
||||
config/icon="res://icon.svg"
|
||||
config/tags=PackedStringArray("demo", "official", "xr")
|
||||
|
||||
[debug]
|
||||
|
||||
gdscript/warnings/untyped_declaration=1
|
||||
|
||||
[rendering]
|
||||
|
||||
|
||||
@@ -4,32 +4,31 @@ signal focus_lost
|
||||
signal focus_gained
|
||||
signal pose_recentered
|
||||
|
||||
@export var maximum_refresh_rate : int = 90
|
||||
@export var maximum_refresh_rate: int = 90
|
||||
|
||||
var xr_interface : OpenXRInterface
|
||||
var xr_is_focussed = false
|
||||
var xr_interface: OpenXRInterface
|
||||
var xr_is_focused := false
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
func _ready() -> void:
|
||||
xr_interface = XRServer.find_interface("OpenXR")
|
||||
if xr_interface and xr_interface.is_initialized():
|
||||
print("OpenXR instantiated successfully.")
|
||||
var vp : Viewport = get_viewport()
|
||||
var vp: Viewport = get_viewport()
|
||||
|
||||
# Enable XR on our viewport
|
||||
# Enable XR on our viewport.
|
||||
vp.use_xr = true
|
||||
|
||||
# Make sure v-sync is off, v-sync is handled by OpenXR
|
||||
# Make sure V-Sync is off, as V-Sync is handled by OpenXR.
|
||||
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
|
||||
|
||||
# Enable VRS
|
||||
# Enable variable rate shading.
|
||||
if RenderingServer.get_rendering_device():
|
||||
vp.vrs_mode = Viewport.VRS_XR
|
||||
elif int(ProjectSettings.get_setting("xr/openxr/foveation_level")) == 0:
|
||||
push_warning("OpenXR: Recommend setting Foveation level to High in Project Settings")
|
||||
|
||||
# Connect the OpenXR events
|
||||
# Connect the OpenXR events.
|
||||
xr_interface.session_begun.connect(_on_openxr_session_begun)
|
||||
xr_interface.session_visible.connect(_on_openxr_visible_state)
|
||||
xr_interface.session_focussed.connect(_on_openxr_focused_state)
|
||||
@@ -41,22 +40,22 @@ func _ready():
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
# Handle OpenXR session ready
|
||||
# Handle OpenXR session ready.
|
||||
func _on_openxr_session_begun() -> void:
|
||||
# Get the reported refresh rate
|
||||
var current_refresh_rate = xr_interface.get_display_refresh_rate()
|
||||
# Get the reported refresh rate.
|
||||
var current_refresh_rate := xr_interface.get_display_refresh_rate()
|
||||
if current_refresh_rate > 0:
|
||||
print("OpenXR: Refresh rate reported as ", str(current_refresh_rate))
|
||||
else:
|
||||
print("OpenXR: No refresh rate given by XR runtime")
|
||||
|
||||
# See if we have a better refresh rate available
|
||||
var new_rate = current_refresh_rate
|
||||
var available_rates : Array = xr_interface.get_available_display_refresh_rates()
|
||||
if available_rates.size() == 0:
|
||||
# See if we have a better refresh rate available.
|
||||
var new_rate := current_refresh_rate
|
||||
var available_rates: Array[float] = xr_interface.get_available_display_refresh_rates()
|
||||
if available_rates.is_empty():
|
||||
print("OpenXR: Target does not support refresh rate extension")
|
||||
elif available_rates.size() == 1:
|
||||
# Only one available, so use it
|
||||
# Only one available, so use it.
|
||||
new_rate = available_rates[0]
|
||||
else:
|
||||
for rate in available_rates:
|
||||
@@ -69,20 +68,21 @@ func _on_openxr_session_begun() -> void:
|
||||
xr_interface.set_display_refresh_rate(new_rate)
|
||||
current_refresh_rate = new_rate
|
||||
|
||||
# Now match our physics rate
|
||||
Engine.physics_ticks_per_second = current_refresh_rate
|
||||
# Now match our physics rate. This is currently needed to avoid jittering,
|
||||
# due to physics interpolation not being used.
|
||||
Engine.physics_ticks_per_second = roundi(current_refresh_rate)
|
||||
|
||||
|
||||
# Handle OpenXR visible state
|
||||
func _on_openxr_visible_state() -> void:
|
||||
# We always pass this state at startup,
|
||||
# but the second time we get this it means our player took off their headset
|
||||
if xr_is_focussed:
|
||||
# but the second time we get this, it means our player took off their headset.
|
||||
if xr_is_focused:
|
||||
print("OpenXR lost focus")
|
||||
|
||||
xr_is_focussed = false
|
||||
xr_is_focused = false
|
||||
|
||||
# pause our game
|
||||
# Pause our game.
|
||||
process_mode = Node.PROCESS_MODE_DISABLED
|
||||
|
||||
focus_lost.emit()
|
||||
@@ -91,19 +91,19 @@ func _on_openxr_visible_state() -> void:
|
||||
# Handle OpenXR focused state
|
||||
func _on_openxr_focused_state() -> void:
|
||||
print("OpenXR gained focus")
|
||||
xr_is_focussed = true
|
||||
xr_is_focused = true
|
||||
|
||||
# unpause our game
|
||||
# Unpause our game.
|
||||
process_mode = Node.PROCESS_MODE_INHERIT
|
||||
|
||||
focus_gained.emit()
|
||||
|
||||
# Handle OpenXR stopping state
|
||||
# Handle OpenXR stopping state.
|
||||
func _on_openxr_stopping() -> void:
|
||||
# Our session is being stopped.
|
||||
print("OpenXR is stopping")
|
||||
|
||||
# Handle OpenXR pose recentered signal
|
||||
# Handle OpenXR pose recentered signal.
|
||||
func _on_openxr_pose_recentered() -> void:
|
||||
# User recentered view, we have to react to this by recentering the view.
|
||||
# This is game implementation dependent.
|
||||
|
||||
Reference in New Issue
Block a user