Files
2026-06-17 15:28:56 -07:00

386 lines
13 KiB
GDScript

@tool
extends Node3D
@onready var perspective = $XROrigin3D/Perspective
@onready var look_recenter_timer:Timer = Timer.new()
@export var right_controller:XRController3D
const mouse_look_sensitivity: float = 0.001
const gamepad_look_sensitivity_deg: float = 90.0
const gamepad_look_deadzone: float = 0.15
var _use_prompt_1:bool = false
var _use_prompt_2:bool = false
@export var use_prompt_1:bool:
get:
return _use_prompt_1
set(val):
_use_prompt_1 = val
if (val):
$prompt_1_timer.start(prompt_1_time)
else:
$prompt_1_timer.stop()
@export var prompt_1_time:int
@export var prompt_2_time:int
@export var use_prompt_2:bool:
get:
return _use_prompt_2
set(val):
_use_prompt_2 = val
if (val and $prompt_2_timer):
$prompt_2_timer.start(prompt_2_time)
else:
$prompt_2_timer.stop()
@export var stage_music:AudioStreamMP3 = null
@onready var is_centering:bool = false
var _tunnel_1_color:Color = Color.WHITE
var _tunnel_2_color:Color = Color.WHITE
var _tunnel_3_color:Color = Color.WHITE
var _tunnel_1_spiral_color:Color = Color(0.8, 0.8, 0.8, 1)
var _tunnel_2_spiral_color:Color = Color(0.8, 0.8, 0.8, 1)
var _tunnel_3_spiral_color:Color = Color(0.8, 0.8, 0.8, 1)
var _tunnel_1_spiral_turns:float = 1.0
var _tunnel_2_spiral_turns:float = 8.0
var _tunnel_3_spiral_turns:float = 1.0
var _tunnel_1_spiral_swirl:float = 6.0
var _tunnel_2_spiral_swirl:float = 6.0
var _tunnel_3_spiral_swirl:float = 6.0
var _tunnel_1_spiral_width:float = 0.047
var _tunnel_2_spiral_width:float = 0.047
var _tunnel_3_spiral_width:float = 0.047
var _tunnel_1_spiral_strands:float = 1.0
var _tunnel_2_spiral_strands:float = 1.0
var _tunnel_3_spiral_strands:float = 1.0
@export var tunnel_1_color:Color = Color.WHITE:
get: return _tunnel_1_color
set(val):
_tunnel_1_color = val
if $MeshInstance3D:
_set_mesh_shader_parameter($MeshInstance3D, "color", val)
@export var tunnel_2_color:Color = Color.WHITE:
get: return _tunnel_2_color
set(val):
_tunnel_2_color = val
if $MeshInstance3D/MeshInstance3D2:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "color", val)
@export var tunnel_3_color:Color = Color.WHITE:
get: return _tunnel_3_color
set(val):
_tunnel_3_color = val
if $MeshInstance3D/MeshInstance3D3:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "color", val)
if $MeshInstance3D/Blurrycap:
_set_blurrycap_shader_parameter("tint_color", val)
@export var tunnel_1_spiral_color:Color = Color(0.8, 0.8, 0.8, 1):
get: return _tunnel_1_spiral_color
set(val):
_tunnel_1_spiral_color = val
if $MeshInstance3D:
_set_mesh_shader_parameter($MeshInstance3D, "spiral_color", val)
@export var tunnel_2_spiral_color:Color = Color(0.8, 0.8, 0.8, 1):
get: return _tunnel_2_spiral_color
set(val):
_tunnel_2_spiral_color = val
if $MeshInstance3D/MeshInstance3D2:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_color", val)
@export var tunnel_3_spiral_color:Color = Color(0.8, 0.8, 0.8, 1):
get: return _tunnel_3_spiral_color
set(val):
_tunnel_3_spiral_color = val
if $MeshInstance3D/MeshInstance3D3:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_color", val)
@export_range(1.0, 48.0) var tunnel_1_spiral_turns:float = 1.0:
get: return _tunnel_1_spiral_turns
set(val):
_tunnel_1_spiral_turns = val
if $MeshInstance3D:
_set_mesh_shader_parameter($MeshInstance3D, "spiral_turns", val)
@export_range(1.0, 48.0) var tunnel_2_spiral_turns:float = 8.0:
get: return _tunnel_2_spiral_turns
set(val):
_tunnel_2_spiral_turns = val
if $MeshInstance3D/MeshInstance3D2:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_turns", val)
@export_range(1.0, 48.0) var tunnel_3_spiral_turns:float = 1.0:
get: return _tunnel_3_spiral_turns
set(val):
_tunnel_3_spiral_turns = val
if $MeshInstance3D/MeshInstance3D3:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_turns", val)
@export_range(6.0, 360.0) var tunnel_1_spiral_swirl:float = 6.0:
get: return _tunnel_1_spiral_swirl
set(val):
_tunnel_1_spiral_swirl = val
if $MeshInstance3D:
_set_mesh_shader_parameter($MeshInstance3D, "spiral_swirl", val)
@export_range(6.0, 360.0) var tunnel_2_spiral_swirl:float = 6.0:
get: return _tunnel_2_spiral_swirl
set(val):
_tunnel_2_spiral_swirl = val
if $MeshInstance3D/MeshInstance3D2:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_swirl", val)
@export_range(6.0, 360.0) var tunnel_3_spiral_swirl:float = 6.0:
get: return _tunnel_3_spiral_swirl
set(val):
_tunnel_3_spiral_swirl = val
if $MeshInstance3D/MeshInstance3D3:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_swirl", val)
@export_range(0.02, 0.5) var tunnel_1_spiral_width:float = 0.047:
get: return _tunnel_1_spiral_width
set(val):
_tunnel_1_spiral_width = val
if $MeshInstance3D:
_set_mesh_shader_parameter($MeshInstance3D, "spiral_width", val)
@export_range(0.02, 0.5) var tunnel_2_spiral_width:float = 0.047:
get: return _tunnel_2_spiral_width
set(val):
_tunnel_2_spiral_width = val
if $MeshInstance3D/MeshInstance3D2:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_width", val)
@export_range(0.02, 0.5) var tunnel_3_spiral_width:float = 0.047:
get: return _tunnel_3_spiral_width
set(val):
_tunnel_3_spiral_width = val
if $MeshInstance3D/MeshInstance3D3:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_width", val)
@export_range(1.0, 2.0) var tunnel_1_spiral_strands:float = 1.0:
get: return _tunnel_1_spiral_strands
set(val):
_tunnel_1_spiral_strands = val
if $MeshInstance3D:
_set_mesh_shader_parameter($MeshInstance3D, "spiral_strands", val)
@export_range(1.0, 2.0) var tunnel_2_spiral_strands:float = 1.0:
get: return _tunnel_2_spiral_strands
set(val):
_tunnel_2_spiral_strands = val
if $MeshInstance3D/MeshInstance3D2:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_strands", val)
@export_range(1.0, 2.0) var tunnel_3_spiral_strands:float = 1.0:
get: return _tunnel_3_spiral_strands
set(val):
_tunnel_3_spiral_strands = val
if $MeshInstance3D/MeshInstance3D3:
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_strands", val)
func _enter_tree() -> void:
if Engine.is_editor_hint():
set_process(true)
call_deferred("_apply_tunnel_shader_properties")
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
_apply_tunnel_shader_properties()
# Keep editor behavior limited to visual parameter syncing.
if Engine.is_editor_hint():
return
# Re-trigger setters now that the scene tree is ready.
add_child(look_recenter_timer)
look_recenter_timer.connect("timeout",_look_recenter_timer_timeout)
look_recenter_timer.one_shot = true
look_recenter_timer.autostart = false
look_recenter_timer.stop()
# As a PC game, we want to eat the mouse cursor like an FPS.
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
# _ensure_gamepad_look_actions()
if use_prompt_1:
$prompt_2_timer.start(169)
if use_prompt_2:
$prompt_1_timer.start(69)
# Initialize VR
_init_vr()
# Wait one frame for XR to be fully set up, then center the headset
await get_tree().process_frame
if get_viewport().use_xr:
XRServer.center_on_hmd(XRServer.DONT_RESET_ROTATION, false)
else:
# go fullscreen - this is a computer.
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
# Begin the portal
_prepare_music()
_begin_portal()
$XROrigin3D/AudioStreamPlayer.play()
func _apply_tunnel_shader_properties() -> void:
var mesh_1 := get_node_or_null("MeshInstance3D") as MeshInstance3D
var mesh_2 := get_node_or_null("MeshInstance3D/MeshInstance3D2") as MeshInstance3D
var mesh_3 := get_node_or_null("MeshInstance3D/MeshInstance3D3") as MeshInstance3D
if mesh_1:
_set_mesh_shader_parameter(mesh_1, "color", _tunnel_1_color)
_set_mesh_shader_parameter(mesh_1, "spiral_color", _tunnel_1_spiral_color)
_set_mesh_shader_parameter(mesh_1, "spiral_turns", _tunnel_1_spiral_turns)
_set_mesh_shader_parameter(mesh_1, "spiral_swirl", _tunnel_1_spiral_swirl)
_set_mesh_shader_parameter(mesh_1, "spiral_width", _tunnel_1_spiral_width)
_set_mesh_shader_parameter(mesh_1, "spiral_strands", _tunnel_1_spiral_strands)
if mesh_2:
_set_mesh_shader_parameter(mesh_2, "color", _tunnel_2_color)
_set_mesh_shader_parameter(mesh_2, "spiral_color", _tunnel_2_spiral_color)
_set_mesh_shader_parameter(mesh_2, "spiral_turns", _tunnel_2_spiral_turns)
_set_mesh_shader_parameter(mesh_2, "spiral_swirl", _tunnel_2_spiral_swirl)
_set_mesh_shader_parameter(mesh_2, "spiral_width", _tunnel_2_spiral_width)
_set_mesh_shader_parameter(mesh_2, "spiral_strands", _tunnel_2_spiral_strands)
if mesh_3:
_set_mesh_shader_parameter(mesh_3, "color", _tunnel_3_color)
_set_mesh_shader_parameter(mesh_3, "spiral_color", _tunnel_3_spiral_color)
_set_mesh_shader_parameter(mesh_3, "spiral_turns", _tunnel_3_spiral_turns)
_set_mesh_shader_parameter(mesh_3, "spiral_swirl", _tunnel_3_spiral_swirl)
_set_mesh_shader_parameter(mesh_3, "spiral_width", _tunnel_3_spiral_width)
_set_mesh_shader_parameter(mesh_3, "spiral_strands", _tunnel_3_spiral_strands)
_set_blurrycap_shader_parameter("tint_color", _tunnel_3_color)
func _prepare_music()->void:
$XROrigin3D/AudioStreamPlayer.stream=stage_music
func _cycle_presentation_format() -> void:
var emitter := $MeshInstance3D/EmissionPoint
if not emitter.is_node_ready():
return
emitter.cycle_format()
func _set_mesh_shader_parameter(
mesh_instance: MeshInstance3D,
parameter: StringName,
val: Variant
) -> void:
var mesh := mesh_instance.mesh as CylinderMesh
if not mesh:
return
var shader_material := mesh.material as ShaderMaterial
if shader_material:
shader_material.set_shader_parameter(parameter, val)
func _set_blurrycap_shader_parameter(parameter: StringName, val: Variant) -> void:
var blurrycap := get_node_or_null("MeshInstance3D/Blurrycap") as MeshInstance3D
if not blurrycap:
return
var shader_material := blurrycap.get_surface_override_material(0) as ShaderMaterial
if shader_material:
shader_material.set_shader_parameter(parameter, val)
func _begin_portal() -> void:
var emitter := $MeshInstance3D/EmissionPoint
emitter.set_viewer_camera(perspective)
await emitter.initialize_video_pool()
func _init_vr():
if (XRServer.get_interface_count() > 0):
var xr_interface = XRServer.find_interface("OpenXR")
if xr_interface and xr_interface.is_initialized():
print("OpenXR initialized successfully")
# Turn off v-sync!
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
# Change our main viewport to output to the HMD
get_viewport().use_xr = true
else:
print("OpenXR not initialized, please check if your headset is connected")
func _input(event:InputEvent) ->void:
if Engine.is_editor_hint():
return
if event.is_action_pressed("Quit"):
get_tree().quit(0)
elif event.is_action_pressed("Fullscreen"):
if DisplayServer.window_get_mode() != DisplayServer.WINDOW_MODE_FULLSCREEN:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
else:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
if event.is_action_pressed("CycleFormat"):
_cycle_presentation_format()
func _process(delta: float) -> void:
if Engine.is_editor_hint():
_apply_tunnel_shader_properties()
return
# Desktop gamepad look is disabled while XR output is active.
_do_gamepad_movement(gamepad_look_sensitivity_deg, delta)
if $XROrigin3D/XRController3D.get_float("trigger") > 0:
_cycle_presentation_format()
_do_autocentering(delta)
func _do_autocentering(delta:float)->void:
if is_centering:
var target_rotation = Vector3.ZERO
var recenter_speed = 0.05 # radians per second
var rotation_delta = target_rotation - perspective.rotation
rotation_delta.x = angle_difference(perspective.rotation.x, target_rotation.x)
rotation_delta.y = angle_difference(perspective.rotation.y, target_rotation.y)
perspective.rotation += rotation_delta.normalized() * recenter_speed * delta
if rotation_delta.length() < 0.01:
is_centering = false
perspective.rotation = Vector3(0, perspective.rotation.z, 0)
func _unhandled_input(event: InputEvent) -> void:
if Engine.is_editor_hint():
return
if (event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED) :
var e = event as InputEventMouseMotion
_apply_look_delta(
mouse_look_sensitivity * -e.relative.x,
mouse_look_sensitivity * -e.relative.y
)
look_recenter_timer.start(1)
func _apply_look_delta(yaw_delta: float, pitch_delta: float) -> void:
perspective.rotate_y(yaw_delta)
perspective.rotate_x(pitch_delta)
perspective.rotation.x = clampf(perspective.rotation.x, -deg_to_rad(50), deg_to_rad(50))
perspective.rotation.y = clampf(perspective.rotation.y, -deg_to_rad(35), deg_to_rad(35))
perspective.rotation.z = 0
func _do_gamepad_movement(gamepad_look_sensitivity_deg:float, delta:float)->void:
if get_viewport().use_xr:
return
var look_input := Vector2(
Input.get_axis("look_left", "look_right"),
Input.get_axis("look_up", "look_down")
)
if look_input.length_squared() < gamepad_look_deadzone * gamepad_look_deadzone:
return
_apply_look_delta(
deg_to_rad(-look_input.x * gamepad_look_sensitivity_deg * delta),
deg_to_rad(-look_input.y * gamepad_look_sensitivity_deg * delta)
)
if look_input!=Vector2.ZERO:
# You moved!
look_recenter_timer.start(1.5) # seconds of no motion until auto recenter.
func _look_recenter_timer_timeout():
is_centering = true