Skip to content

Commit

Permalink
Added passing of data between staged scenes
Browse files Browse the repository at this point in the history
Added passing of user_data between scenes.
Added default handling of string/vector3/transform3d user_data as spawn-point.
Added extended documentation about staging signals and methods.
Modified demo teleporter to support optional spawn-point data.
Add minor-breakage comment to VERSIONS.md.
Disable warnings for unused parameters on interface functions intended for overriding.
Added support for user_data objects with "get_spawn_position" method.
  • Loading branch information
Malcolmnixon committed Aug 21, 2023
1 parent 154e861 commit a8622d0
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 73 deletions.
2 changes: 2 additions & 0 deletions VERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
- Modified pickup highlighting to support pickables in snap-zones
- Added "UI Objects" layer 23 for viewports to support interaction by pointer and poking
- Fixed player scaling issues with crouching and poke
- **minor-breakage** Added support for passing user data between staged scenes with default handling for spawn-points


# 4.1.0
- Enhanced grappling to support collision and target layers
Expand Down
134 changes: 103 additions & 31 deletions addons/godot-xr-tools/staging/scene_base.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,55 @@
class_name XRToolsSceneBase
extends Node3D

## Introduction
#
# This is our base scene for all our levels.
# It ensures that we have all bits in place to load
# our scene into our staging scene.


## Request staging exit to main menu
## XR Tools Scene Base Class
##
## This is our base scene for all our levels. It ensures that we have all bits
## in place to load our scene into our staging scene.
##
## Developers can customize scene transitions by extending from this class and
## overriding the [method scene_loaded] behavior.


## This signal is used to request the staging transition to the main-menu
## scene. Developers should use [method exit_to_main_menu] rather than
## emitting this signal directly.
signal request_exit_to_main_menu

## Request staging load a new scene
##
## This signal is used to request the staging transition to the specified
## scene. Developers should use [method load_scene] rather than emitting
## this signal directly.
signal request_load_scene(p_scene_path)

## Request staging reload the current scene
##
## The [param user_data] parameter is passed through staging to the new scenes.
signal request_load_scene(p_scene_path, user_data)

## This signal is used to request the staging reload this scene. Developers
## should use [method reset_scene] rather than emitting this signal directly.
signal request_reset_scene
##
## The [param user_data] parameter is passed through staging to the new scenes.
signal request_reset_scene(user_data)


# This file contains methods with parameters that are unused; however they are
# documented and intended to be overridden in derived classes. As such unused
# parameter warnings need to be disabled.
#
# warning-ignore:unused_parameter
# gdlint:disable=unused-argument


## Interface

func _ready() -> void:
pass


# Add support for is_xr_class on XRTools classes
func is_xr_class(name : String) -> bool:
return name == "XRToolsSceneBase"


## This method center the player on the [param p_transform] transform.
func center_player_on(p_transform : Transform3D):
# In order to center our player so the players feet are at the location
# indicated by p_transform, and having our player looking in the required
Expand All @@ -60,28 +72,83 @@ func center_player_on(p_transform : Transform3D):
# And now update our origin point
$XROrigin3D.global_transform = (p_transform * transform.inverse()).orthonormalized()

func scene_loaded():

## This method is called when the scene is loaded, but before it becomes visible.
##
## The [param user_data] parameter is an optional parameter passed in when the
## scene is loaded - usually from the previous scene. By default the
## user_data can be a [String] spawn-point node-name, [Vector3], [Transform3D],
## an object with a 'get_spawn_position' method, or null to spawn at the scenes
## [XROrigin3D] location.
##
## Advanced scene-transition functionality can be implemented by overriding this
## method and calling the super() with any desired spawn transform. This could
## come from a field of an advanced user_data class-object, or from a game-state
## singleton.
func scene_loaded(user_data = null):
# Called after scene is loaded

# Make sure our camera becomes the current camera
$XROrigin3D/XRCamera3D.current = true
$XROrigin3D.current = true

# Center our player on our origin point
# Note, this means you can place the XROrigin3D point in the start
# position where you want the player to spawn, even if the player is
# physically halfway across the room.
center_player_on($XROrigin3D.global_transform)
# Start by assuming the user_data contains spawn position information.
var spawn_position = user_data

# If the user_data is an object with a 'get_spawn_position' method then
# call it (with this [XRToolsSceneBase] allowing it to inspect the scene
# if necessary) and use the return value as the spawn position information.
if typeof(user_data) == TYPE_OBJECT and user_data.has_method("get_spawn_position"):
spawn_position = user_data.get_spawn_position(self)

func scene_visible():
# Get the spawn [Transform3D] by inspecting the spawn position value for
# standard types of spawn position information:
# - null to use the standard XROrigin3D location
# - String name of a Node3D to spawn at
# - Vector3 to spawn at
# - Transform3D to spawn at
var spawn_transform : Transform3D = $XROrigin3D.global_transform
match typeof(spawn_position):
TYPE_STRING: # Name of Node3D to spawn at
var node = find_child(spawn_position)
if node is Node3D:
spawn_transform = node.global_transform

TYPE_VECTOR3: # Vector3 to spawn at (rotation comes from XROrigin3D)
spawn_transform.origin = spawn_position

TYPE_TRANSFORM3D: # Transform3D spawn location
spawn_transform = spawn_position

# Center the player on the spawn location
center_player_on(spawn_transform)


## This method is called when the scene becomes fully visible to the user.
##
## The [param user_data] parameter is an optional parameter passed in when the
## scene is loaded - usually from the previous scene.
func scene_visible(user_data = null):
# Called after the scene becomes fully visible
pass

func scene_pre_exiting():

## This method is called before the start of transition from this scene to a
## new scene.
##
## The [param user_data] parameter is an optional parameter passed in when the
## scene transition is requested.
func scene_pre_exiting(user_data = null):
# Called before we start fading out and removing our scene
pass

func scene_exiting():

## This method is called immediately before this scene is unloaded.
##
##
## The [param user_data] parameter is an optional parameter passed in when the
## scene transition is requested.
func scene_exiting(user_data = null):
# called right before we remove this scene
pass

Expand All @@ -97,26 +164,31 @@ func exit_to_main_menu() -> void:
emit_signal("request_exit_to_main_menu")


## Transition to specific scene
##
## This function is used to transition to the specified scene. The default
## implementation sends the [signal request_load_scene].
##
## Custom scene classes can override this function to add their logic, but
## should usually call this super method.
func load_scene(p_scene_path : String) -> void:
emit_signal("request_load_scene", p_scene_path)
##
## The [param user_data] parameter is passed to the new scene, and can be used
## to relay information through the transition. The default behavior of
## [method scene_loaded] will attempt to interpret it as a spawn-point for the
## player as node-name, Vector3, or Transform3D.
##
## See [method scene_loaded] for options to provide advanced scene-transition
## functionality.
func load_scene(p_scene_path : String, user_data = null) -> void:
emit_signal("request_load_scene", p_scene_path, user_data)


## Reset current scene
##
## This function is used to reset the current scene. The default
## implementation sends the [signal request_reset_scene] which triggers
## a reload of the current scene.
##
## Custom scene classes can override this method to implement faster reset
## logic than is performed by the brute-force scene-reload performed by
## staging.
func reset_scene() -> void:
emit_signal("request_reset_scene")

##
## Any [param user_data] provided is passed into the new scene.
func reset_scene(user_data = null) -> void:
emit_signal("request_reset_scene", user_data)
81 changes: 51 additions & 30 deletions addons/godot-xr-tools/staging/staging.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class_name XRToolsStaging
extends Node3D


## XR Tools Staging
## XR Tools Staging Class
##
## When creating a game with multiple levels where you want to
## make use of background loading and have some nice structure
Expand All @@ -28,22 +28,36 @@ extends Node3D
## explained in individual demos found here.


## Current scene is being unloaded
signal scene_exiting(scene)
## This signal is emitted when the current scene starts to be unloaded. The
## [param scene] parameter is the path of the current scene, and the
## [param user_data] parameter is the optional data passed from the
## current scene to the next.
signal scene_exiting(scene, user_data)

## Switched to the loading scene
signal switching_to_loading_scene
## This signal is emitted when the old scene has been unloaded and the user
## is fading into the loading scene. The [param user_data] parameter is the
## optional data provided by the old scene.
signal switching_to_loading_scene(user_data)

## New scene has been loaded
signal scene_loaded(scene)
## This signal is emitted when the new scene has been loaded before it becomes
## visible. The [param scene] parameter is the path of the new scene, and the
## [param user_data] parameter is the optional data passed from the old scene
## to the new scene.
signal scene_loaded(scene, user_data)

## New scene is now visible
signal scene_visible(scene)
## This signal is emitted when the new scene has become fully visible to the
## player. The [param scene] parameter is the path of the new scene, and the
## [param user_data] parameter is the optional data passed from the old scene
## to the new scene.
signal scene_visible(scene, user_data)

## XR interaction started
## This signal is invoked when the XR experience starts.
signal xr_started

## XR interaction ended
## This signal is invoked when the XR experience ends. This usually occurs when
## the player removes the headset. The game may want to react by pausing until
## the player puts the headset back on and the [signal xr_started] signal is
## emitted.
signal xr_ended


Expand All @@ -54,19 +68,19 @@ signal xr_ended
@export var prompt_for_continue : bool = true


# Current scene
## The current scene
var current_scene : XRToolsSceneBase

# Current scene path
## The current scene path
var current_scene_path : String

# Tween for fading
var _tween : Tween

## XR Origin
## The [XROrigin3D] node used while staging
@onready var xr_origin : XROrigin3D = XRHelpers.get_xr_origin(self)

## XR Camera
## The [XRCamera3D] node used while staging
@onready var xr_camera : XRCamera3D = XRHelpers.get_xr_camera(self)


Expand Down Expand Up @@ -114,8 +128,14 @@ func is_xr_class(name : String) -> bool:
return name == "XRToolsStaging"


## Load the specified scene
func load_scene(p_scene_path : String) -> void:
## This function loads the [param p_scene_path] scene file.
##
## The [param user_data] parameter contains optional data passed from the old
## scene to the new scene.
##
## See [method XRToolsSceneBase.scene_loaded] for details on how to implement
## advanced scene-switching.
func load_scene(p_scene_path : String, user_data = null) -> void:
# Do not load if in the editor
if Engine.is_editor_hint():
return
Expand All @@ -130,7 +150,7 @@ func load_scene(p_scene_path : String) -> void:
# Start by unloading our scene

# Let the scene know we're about to remove it
current_scene.scene_pre_exiting()
current_scene.scene_pre_exiting(user_data)

# Remove signals
_remove_signals(current_scene)
Expand All @@ -143,8 +163,8 @@ func load_scene(p_scene_path : String) -> void:
await _tween.finished

# Now we remove our scene
emit_signal("scene_exiting", current_scene)
current_scene.scene_exiting()
emit_signal("scene_exiting", current_scene, user_data)
current_scene.scene_exiting(user_data)
$Scene.remove_child(current_scene)
current_scene.queue_free()
current_scene = null
Expand All @@ -157,7 +177,7 @@ func load_scene(p_scene_path : String) -> void:
$LoadingScreen.enable_press_to_continue = false
$LoadingScreen.follow_camera = true
$LoadingScreen.visible = true
emit_signal("switching_to_loading_scene")
switching_to_loading_scene.emit(user_data)

# Fade to visible
if _tween:
Expand Down Expand Up @@ -217,8 +237,8 @@ func load_scene(p_scene_path : String) -> void:

# We create a small delay here to give tracking some time to update our nodes...
await get_tree().create_timer(0.1).timeout
current_scene.scene_loaded()
emit_signal("scene_loaded", current_scene)
current_scene.scene_loaded(user_data)
scene_loaded.emit(current_scene, user_data)

# Fade to visible
if _tween:
Expand All @@ -227,11 +247,12 @@ func load_scene(p_scene_path : String) -> void:
_tween.tween_method(set_fade, 1.0, 0.0, 1.0)
await _tween.finished

current_scene.scene_visible()
emit_signal("scene_visible", current_scene)
current_scene.scene_visible(user_data)
scene_visible.emit(current_scene, user_data)


## Fade
## This method sets the fade-alpha for scene transitions. The [param p_value]
## parameter must be in the range [0.0 - 1.0].
##
## Our fade object allows us to black out the screen for transitions.
## Note that our AABB is set to HUGE so it should always be rendered
Expand Down Expand Up @@ -262,12 +283,12 @@ func _on_exit_to_main_menu():
load_scene(main_scene)


func _on_load_scene(p_scene_path : String):
load_scene(p_scene_path)
func _on_load_scene(p_scene_path : String, user_data):
load_scene(p_scene_path, user_data)


func _on_reset_scene():
load_scene(current_scene_path)
func _on_reset_scene(user_data):
load_scene(current_scene_path, user_data)


func _on_StartXR_xr_started():
Expand Down
Loading

0 comments on commit a8622d0

Please sign in to comment.