315 lines
7.7 KiB
GDScript
315 lines
7.7 KiB
GDScript
extends Node
|
|
|
|
var music_player: AudioStreamPlayer
|
|
var ambient_loop: AudioStreamPlayer
|
|
var whale_player: AudioStreamPlayer
|
|
var swim_loop_player: AudioStreamPlayer
|
|
var boost_player: AudioStreamPlayer
|
|
|
|
var _whale_timer: Timer
|
|
var _music_tween: Tween
|
|
|
|
const MUSIC_PATH := "res://audio/music/"
|
|
const SFX_PATH := "res://audio/sfx/"
|
|
|
|
# Generated stream cache (AudioStreamGenerator-based placeholders)
|
|
var _gen_streams: Dictionary = {}
|
|
|
|
func _ready() -> void:
|
|
music_player = AudioStreamPlayer.new()
|
|
music_player.bus = "Music"
|
|
music_player.volume_db = -10.0
|
|
add_child(music_player)
|
|
|
|
ambient_loop = AudioStreamPlayer.new()
|
|
ambient_loop.bus = "SFX"
|
|
ambient_loop.volume_db = -12.0
|
|
add_child(ambient_loop)
|
|
|
|
whale_player = AudioStreamPlayer.new()
|
|
whale_player.bus = "SFX"
|
|
whale_player.volume_db = -15.0
|
|
add_child(whale_player)
|
|
|
|
# Swim loop player (continuous while moving)
|
|
swim_loop_player = AudioStreamPlayer.new()
|
|
swim_loop_player.bus = "SFX"
|
|
swim_loop_player.volume_db = -18.0
|
|
add_child(swim_loop_player)
|
|
|
|
# Boost player (one-shot on boost start)
|
|
boost_player = AudioStreamPlayer.new()
|
|
boost_player.bus = "SFX"
|
|
boost_player.volume_db = -10.0
|
|
add_child(boost_player)
|
|
|
|
_whale_timer = Timer.new()
|
|
_whale_timer.one_shot = true
|
|
_whale_timer.timeout.connect(_on_whale_timer)
|
|
add_child(_whale_timer)
|
|
_schedule_next_whale()
|
|
|
|
|
|
# Returns (or creates) a silent AudioStreamGenerator for placeholder sounds.
|
|
func _get_silent_stream(duration_sec: float = 0.5) -> AudioStreamGenerator:
|
|
var key := "silent_%.1f" % duration_sec
|
|
if _gen_streams.has(key):
|
|
return _gen_streams[key]
|
|
var gen := AudioStreamGenerator.new()
|
|
gen.mix_rate = 22050.0
|
|
gen.buffer_length = duration_sec
|
|
_gen_streams[key] = gen
|
|
return gen
|
|
|
|
|
|
func play_music(track_name: String) -> void:
|
|
var path := MUSIC_PATH + track_name
|
|
if not ResourceLoader.exists(path):
|
|
return
|
|
|
|
var stream: AudioStream = load(path)
|
|
if stream == null:
|
|
return
|
|
|
|
music_player.stream = stream
|
|
music_player.stream.loop = true
|
|
music_player.volume_db = -40.0
|
|
music_player.play()
|
|
|
|
if _music_tween:
|
|
_music_tween.kill()
|
|
_music_tween = create_tween()
|
|
_music_tween.tween_property(music_player, "volume_db", -10.0, 3.0).set_trans(Tween.TRANS_SINE)
|
|
|
|
|
|
func play_ambient_loop(loop_name: String) -> void:
|
|
var path := SFX_PATH + loop_name
|
|
if not ResourceLoader.exists(path):
|
|
# Fall back to silent generator so the slot is occupied
|
|
ambient_loop.stream = _get_silent_stream(2.0)
|
|
return
|
|
|
|
var stream: AudioStream = load(path)
|
|
if stream == null:
|
|
return
|
|
|
|
ambient_loop.stream = stream
|
|
ambient_loop.stream.loop = true
|
|
ambient_loop.play()
|
|
|
|
|
|
func play_whale_call_random() -> void:
|
|
var path := SFX_PATH + "whale_call.ogg"
|
|
if not ResourceLoader.exists(path):
|
|
return
|
|
if whale_player.playing:
|
|
return
|
|
|
|
var stream: AudioStream = load(path)
|
|
if stream == null:
|
|
return
|
|
|
|
whale_player.stream = stream
|
|
whale_player.play()
|
|
|
|
|
|
func play_bubble_sfx(position: Vector3) -> void:
|
|
var path := SFX_PATH + "bubbles.ogg"
|
|
var player := AudioStreamPlayer3D.new()
|
|
player.bus = "SFX"
|
|
player.volume_db = -8.0
|
|
player.max_distance = 20.0
|
|
player.attenuation_model = AudioStreamPlayer3D.ATTENUATION_INVERSE_SQUARE_DISTANCE
|
|
add_child(player)
|
|
player.global_position = position
|
|
|
|
if ResourceLoader.exists(path):
|
|
var stream: AudioStream = load(path)
|
|
if stream != null:
|
|
player.stream = stream
|
|
player.play()
|
|
player.finished.connect(player.queue_free)
|
|
return
|
|
|
|
# Placeholder: silent generator
|
|
player.stream = _get_silent_stream(0.3)
|
|
player.play()
|
|
player.finished.connect(player.queue_free)
|
|
|
|
|
|
# --- New: swim loop ---
|
|
func play_swim_loop() -> void:
|
|
if swim_loop_player.playing:
|
|
return
|
|
var path := SFX_PATH + "swim_loop.ogg"
|
|
if ResourceLoader.exists(path):
|
|
var s: AudioStream = load(path)
|
|
if s != null:
|
|
swim_loop_player.stream = s
|
|
swim_loop_player.play()
|
|
return
|
|
# Silent placeholder keeps the architecture wired
|
|
swim_loop_player.stream = _get_silent_stream(1.0)
|
|
swim_loop_player.play()
|
|
|
|
|
|
func stop_swim_loop() -> void:
|
|
if swim_loop_player.playing:
|
|
swim_loop_player.stop()
|
|
|
|
|
|
# --- New: boost sound ---
|
|
func play_boost() -> void:
|
|
var path := SFX_PATH + "boost.ogg"
|
|
if ResourceLoader.exists(path):
|
|
var s: AudioStream = load(path)
|
|
if s != null:
|
|
boost_player.stream = s
|
|
boost_player.play()
|
|
return
|
|
boost_player.stream = _get_silent_stream(0.4)
|
|
boost_player.play()
|
|
|
|
|
|
# --- New: block break ---
|
|
func play_block_break(position: Vector3) -> void:
|
|
var path := SFX_PATH + "block_break.ogg"
|
|
var player := AudioStreamPlayer3D.new()
|
|
player.bus = "SFX"
|
|
player.volume_db = -6.0
|
|
player.max_distance = 15.0
|
|
add_child(player)
|
|
player.global_position = position
|
|
if ResourceLoader.exists(path):
|
|
var s: AudioStream = load(path)
|
|
if s != null:
|
|
player.stream = s
|
|
player.play()
|
|
player.finished.connect(player.queue_free)
|
|
return
|
|
player.stream = _get_silent_stream(0.3)
|
|
player.play()
|
|
player.finished.connect(player.queue_free)
|
|
|
|
|
|
# --- New: echolocation ping ---
|
|
func play_echo_ping(position: Vector3) -> void:
|
|
var path := SFX_PATH + "echo_ping.ogg"
|
|
var player := AudioStreamPlayer3D.new()
|
|
player.bus = "SFX"
|
|
player.volume_db = -4.0
|
|
player.max_distance = 40.0
|
|
add_child(player)
|
|
player.global_position = position
|
|
if ResourceLoader.exists(path):
|
|
var s: AudioStream = load(path)
|
|
if s != null:
|
|
player.stream = s
|
|
player.play()
|
|
player.finished.connect(player.queue_free)
|
|
return
|
|
player.stream = _get_silent_stream(0.5)
|
|
player.play()
|
|
player.finished.connect(player.queue_free)
|
|
|
|
|
|
# --- New: pearl collect ---
|
|
func play_pearl_collect(position: Vector3) -> void:
|
|
var path := SFX_PATH + "pearl_collect.ogg"
|
|
var player := AudioStreamPlayer3D.new()
|
|
player.bus = "SFX"
|
|
player.volume_db = -5.0
|
|
player.max_distance = 20.0
|
|
add_child(player)
|
|
player.global_position = position
|
|
if ResourceLoader.exists(path):
|
|
var s: AudioStream = load(path)
|
|
if s != null:
|
|
player.stream = s
|
|
player.play()
|
|
player.finished.connect(player.queue_free)
|
|
return
|
|
player.stream = _get_silent_stream(0.4)
|
|
player.play()
|
|
player.finished.connect(player.queue_free)
|
|
|
|
|
|
# --- New: death / respawn ---
|
|
func play_death() -> void:
|
|
var path := SFX_PATH + "death.ogg"
|
|
if ResourceLoader.exists(path):
|
|
var s: AudioStream = load(path)
|
|
if s != null:
|
|
var p := AudioStreamPlayer.new()
|
|
p.bus = "SFX"
|
|
p.volume_db = -5.0
|
|
add_child(p)
|
|
p.stream = s
|
|
p.play()
|
|
p.finished.connect(p.queue_free)
|
|
return
|
|
# silent fallback — architecture is wired
|
|
var p2 := AudioStreamPlayer.new()
|
|
p2.bus = "SFX"
|
|
p2.stream = _get_silent_stream(0.6)
|
|
add_child(p2)
|
|
p2.play()
|
|
p2.finished.connect(p2.queue_free)
|
|
|
|
|
|
func play_respawn() -> void:
|
|
var path := SFX_PATH + "respawn.ogg"
|
|
if ResourceLoader.exists(path):
|
|
var s: AudioStream = load(path)
|
|
if s != null:
|
|
var p := AudioStreamPlayer.new()
|
|
p.bus = "SFX"
|
|
p.volume_db = -6.0
|
|
add_child(p)
|
|
p.stream = s
|
|
p.play()
|
|
p.finished.connect(p.queue_free)
|
|
return
|
|
var p2 := AudioStreamPlayer.new()
|
|
p2.bus = "SFX"
|
|
p2.stream = _get_silent_stream(0.5)
|
|
add_child(p2)
|
|
p2.play()
|
|
p2.finished.connect(p2.queue_free)
|
|
|
|
|
|
# --- New: ambient deep sea (low drone, played on top of underwater_ambient) ---
|
|
func play_deep_sea_ambient() -> void:
|
|
var path := SFX_PATH + "deep_sea_ambient.ogg"
|
|
var player := AudioStreamPlayer.new()
|
|
player.bus = "SFX"
|
|
player.volume_db = -20.0
|
|
add_child(player)
|
|
if ResourceLoader.exists(path):
|
|
var s: AudioStream = load(path)
|
|
if s != null:
|
|
player.stream = s
|
|
player.play()
|
|
return
|
|
player.stream = _get_silent_stream(2.0)
|
|
player.play()
|
|
|
|
|
|
func set_music_volume(db: float) -> void:
|
|
music_player.volume_db = db
|
|
|
|
|
|
func set_sfx_volume(db: float) -> void:
|
|
ambient_loop.volume_db = db
|
|
whale_player.volume_db = db - 3.0
|
|
|
|
|
|
func _on_whale_timer() -> void:
|
|
play_whale_call_random()
|
|
_schedule_next_whale()
|
|
|
|
|
|
func _schedule_next_whale() -> void:
|
|
_whale_timer.wait_time = randf_range(30.0, 90.0)
|
|
_whale_timer.start()
|