feat: implement global SFXManager singleton and integrate into main scene initialization
This commit is contained in:
+7
-3
@@ -720,8 +720,12 @@ func _auto_start_from_lobby():
|
|||||||
|
|
||||||
func _start_game():
|
func _start_game():
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
|
# Delay spawn assignment to allow clients to finish instantiating Player nodes
|
||||||
|
# via MultiplayerSpawner. If called too early, the RPC is dropped and clients
|
||||||
|
# are left misplaced at the default starting position.
|
||||||
|
await get_tree().create_timer(1.0).timeout
|
||||||
|
|
||||||
# NOW assign spawn positions for EVERYONE (Host, Client, Bots)
|
# NOW assign spawn positions for EVERYONE (Host, Client, Bots)
|
||||||
# We do this BEFORE the stabilization delay so players are moved away from (0,0) immediately.
|
|
||||||
_assign_random_spawn_positions()
|
_assign_random_spawn_positions()
|
||||||
|
|
||||||
# Wait for Nakama websocket to actually be open, up to 5 seconds
|
# Wait for Nakama websocket to actually be open, up to 5 seconds
|
||||||
@@ -735,9 +739,9 @@ func _start_game():
|
|||||||
wait_time += 0.2
|
wait_time += 0.2
|
||||||
|
|
||||||
# Stabilization delay to allow clients to finish loading and spawning
|
# Stabilization delay to allow clients to finish loading and spawning
|
||||||
# We wait 1.5s to ensure the 1.2s loading screen buffer has finished
|
# We wait 0.5s to ensure the remainder of the 1.2s loading screen buffer has finished
|
||||||
# before the countdown starts.
|
# before the countdown starts.
|
||||||
await get_tree().create_timer(1.5).timeout
|
await get_tree().create_timer(0.5).timeout
|
||||||
|
|
||||||
# PRE-GAME COUNTDOWN (3s)
|
# PRE-GAME COUNTDOWN (3s)
|
||||||
# Spawn static obstacles before countdown starts (Stop n Go only)
|
# Spawn static obstacles before countdown starts (Stop n Go only)
|
||||||
|
|||||||
+19
-1
@@ -76,6 +76,8 @@ var is_attack_mode: bool = false:
|
|||||||
return # Prevent infinite recursion / redundant updates
|
return # Prevent infinite recursion / redundant updates
|
||||||
|
|
||||||
is_attack_mode = value
|
is_attack_mode = value
|
||||||
|
if is_attack_mode:
|
||||||
|
attack_mode_timer = MAX_ATTACK_MODE_TIME
|
||||||
_refresh_player_visuals()
|
_refresh_player_visuals()
|
||||||
|
|
||||||
# Sync to others if we are the authority
|
# Sync to others if we are the authority
|
||||||
@@ -836,6 +838,8 @@ var slow_timer: float = 0.0
|
|||||||
var tekton_carry_timer: float = 0.0
|
var tekton_carry_timer: float = 0.0
|
||||||
const MAX_TEKTON_CARRY_TIME: float = 3.0
|
const MAX_TEKTON_CARRY_TIME: float = 3.0
|
||||||
|
|
||||||
|
var attack_mode_timer: float = 0.0
|
||||||
|
const MAX_ATTACK_MODE_TIME: float = 5.0
|
||||||
|
|
||||||
@rpc("any_peer", "call_local")
|
@rpc("any_peer", "call_local")
|
||||||
func apply_stagger(duration: float = 1.5):
|
func apply_stagger(duration: float = 1.5):
|
||||||
@@ -1184,12 +1188,24 @@ func _process(delta):
|
|||||||
if movement_manager:
|
if movement_manager:
|
||||||
movement_manager._process(delta)
|
movement_manager._process(delta)
|
||||||
|
|
||||||
|
# Attack/Knock Mode Expiration Timer
|
||||||
|
if is_multiplayer_authority() and (is_attack_mode or is_knock_mode):
|
||||||
|
if attack_mode_timer > 0:
|
||||||
|
attack_mode_timer -= delta
|
||||||
|
if attack_mode_timer <= 0:
|
||||||
|
attack_mode_timer = 0.0
|
||||||
|
is_attack_mode = false
|
||||||
|
is_knock_mode = false
|
||||||
|
NotificationManager.send_message(self, "Knock Mode Expired!", NotificationManager.MessageType.WARNING)
|
||||||
|
if powerup_manager:
|
||||||
|
powerup_manager.reset_boost()
|
||||||
|
|
||||||
# Immunity Timer Logic
|
# Immunity Timer Logic
|
||||||
if immunity_timer > 0:
|
if immunity_timer > 0:
|
||||||
immunity_timer -= delta
|
immunity_timer -= delta
|
||||||
if immunity_timer <= 0:
|
if immunity_timer <= 0:
|
||||||
immunity_timer = 0
|
immunity_timer = 0
|
||||||
_apply_tint_recursive(self , Color.WHITE) # Remove immunity tint
|
_apply_tint_recursive(self, Color.WHITE) # Remove immunity tint
|
||||||
|
|
||||||
# Slow Timer Logic
|
# Slow Timer Logic
|
||||||
if slow_timer > 0:
|
if slow_timer > 0:
|
||||||
@@ -2445,6 +2461,8 @@ var is_knock_mode: bool = false:
|
|||||||
set(value):
|
set(value):
|
||||||
if is_knock_mode == value: return
|
if is_knock_mode == value: return
|
||||||
is_knock_mode = value
|
is_knock_mode = value
|
||||||
|
if is_knock_mode:
|
||||||
|
attack_mode_timer = MAX_ATTACK_MODE_TIME
|
||||||
_refresh_player_visuals()
|
_refresh_player_visuals()
|
||||||
|
|
||||||
func enter_attack_mode():
|
func enter_attack_mode():
|
||||||
|
|||||||
@@ -15,10 +15,16 @@ func _load_sounds():
|
|||||||
dir.list_dir_begin()
|
dir.list_dir_begin()
|
||||||
var file_name = dir.get_next()
|
var file_name = dir.get_next()
|
||||||
while file_name != "":
|
while file_name != "":
|
||||||
if not dir.current_is_dir() and (file_name.ends_with(".mp3") or file_name.ends_with(".wav") or file_name.ends_with(".ogg")):
|
if not dir.current_is_dir():
|
||||||
var base_name = file_name.get_basename()
|
# Remove .import extension if it exists (Godot adds this to imported resources in exported builds)
|
||||||
sounds[base_name] = load(sfx_path + file_name)
|
var clean_name = file_name.replace(".import", "")
|
||||||
# print("[SfxManager] Loaded: ", base_name)
|
|
||||||
|
if clean_name.ends_with(".mp3") or clean_name.ends_with(".wav") or clean_name.ends_with(".ogg"):
|
||||||
|
var base_name = clean_name.get_basename() # Ex: "jump.wav" -> "jump"
|
||||||
|
# Only load the original extension, Godot's resource loader handles the .import remapping automatically.
|
||||||
|
if not sounds.has(base_name):
|
||||||
|
sounds[base_name] = load(sfx_path + clean_name)
|
||||||
|
|
||||||
file_name = dir.get_next()
|
file_name = dir.get_next()
|
||||||
dir.list_dir_end()
|
dir.list_dir_end()
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user