xiandie/manager/audio_manager/audio_manager.gd
2025-06-18 21:48:59 +08:00

167 lines
5.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Node
# random players
var sfx_players = [] as Array[AudioStreamPlayer]
var idx = 0
# bgm player
var bgm_dict = {}
# vibe player
func _ready() -> void:
for i in range(5):
var sfx_player = RandomAudioStreamPlayer.new()
sfx_players.append(sfx_player)
sfx_player.bus = "game_sfx"
add_child(sfx_player)
# 初始化基础播放器
_base_player = AudioStreamPlayer.new()
_base_player.name = "BaseAmbiencePlayer"
add_child(_base_player)
# 初始化点缀音播放器池
for i in range(_EMBELLISHMENT_PLAYER_POOL_SIZE):
var player = AudioStreamPlayer.new()
player.name = "EmbellishmentPlayer_" + str(i)
add_child(player)
_embellishment_players.append(player)
func play_sfx(sfx: AudioStream, db := 1.0) -> void:
sfx_players[idx].stream = sfx
sfx_players[idx].volume_db = db
sfx_players[idx].play()
idx = wrapi(idx + 1, 0, 5)
# 挂载并循环播放 bgm 音效
func loop_bgm_music(music_name: StringName, stream: AudioStream, db := 0.0, loop := true) -> void:
var audio_player = bgm_dict.get(music_name) as AudioStreamPlayer
if audio_player:
if audio_player.playing:
print("bgm music already playing: ", music_name)
return
bgm_dict.erase(music_name)
audio_player.stop()
audio_player.queue_free()
audio_player = AudioStreamPlayer.new()
add_child(audio_player)
bgm_dict[music_name] = audio_player
audio_player.stream = stream
audio_player.volume_db = db
audio_player.bus = "game_music"
audio_player.play()
if loop and stream.get_length() > 0:
audio_player.finished.connect(audio_player.play)
func stop_bgm_music(music_name: StringName, ease_duration := 3.0) -> void:
var audio_player = bgm_dict.get(music_name) as AudioStreamPlayer
if audio_player:
if ease_duration <= 0:
remove_child(audio_player)
audio_player.queue_free()
else:
var tween = create_tween()
tween.tween_property(audio_player, "volume_db", -80.0, ease_duration)
tween.tween_callback(audio_player.queue_free)
bgm_dict.erase(music_name)
else:
print("music bgm not found: ", music_name)
#### vibe management
## 负责实际创建 AudioStreamPlayer 节点并播放、管理 VibeGroup。
# 当前正在播放的音轨组资源
var current_vibe_group: VibeGroup = null
# 用于播放基础环境音的播放器
var _base_player: AudioStreamPlayer
# 用于播放点缀音的播放器池。使用池可以处理多个点缀音同时播放的情况。
var _embellishment_players: Array[AudioStreamPlayer] = []
# 用于管理点缀音播放间隔的计时器
var _embellishment_timers: Array[Timer] = []
const _EMBELLISHMENT_PLAYER_POOL_SIZE = 8 # 点缀音播放器池的大小,可根据需求调整
## 核心方法:播放一个指定的 VibeGroup
func play_group(group: VibeGroup):
if not is_instance_valid(group):
printerr("VibeManager: VibeGroup is not valid.")
stop_all()
return
# 如果请求播放的是当前已在播放的组,则忽略
if group == current_vibe_group:
return
stop_all()
current_vibe_group = group
# 播放基础环境音
if is_instance_valid(current_vibe_group.base_sound):
_base_player.stream = current_vibe_group.base_sound
# TODO 设置循环
if _base_player.stream is AudioStreamOggVorbis:
(_base_player.stream as AudioStreamOggVorbis).loop = true
# 注意WAV 默认导入设置中需要勾选 loop
_base_player.volume_db = current_vibe_group.group_db + current_vibe_group.base_sound_db
_base_player.play()
# 设置并启动所有点缀音的计时器
for embellishment in current_vibe_group.embellishments:
if not is_instance_valid(embellishment) or not is_instance_valid(embellishment.sound):
continue
var timer = Timer.new()
timer.one_shot = true
# 使用 lambda 函数或 bind 将点缀音数据传递给超时处理函数
timer.timeout.connect(_on_embellishment_timer_timeout.bind(embellishment, timer))
add_child(timer)
_embellishment_timers.append(timer)
# 首次启动计时器
var random_wait_time = randf_range(embellishment.min_interval, embellishment.max_interval)
timer.start(random_wait_time)
## 停止所有当前播放的音效和计时器
func stop_all():
_base_player.stop()
for player in _embellishment_players:
player.stop()
for timer in _embellishment_timers:
timer.queue_free()
_embellishment_timers.clear()
current_vibe_group = null
# 当某个点缀音的计时器到期时调用
func _on_embellishment_timer_timeout(embellishment: Embellishment, timer: Timer):
# 寻找一个空闲的点缀音播放器
var player = _get_available_embellishment_player()
if is_instance_valid(player):
player.stream = embellishment.sound
player.volume_db = current_vibe_group.group_db + embellishment.db
player.play()
# 重新启动计时器,实现循环随机播放
var random_wait_time = randf_range(embellishment.min_interval, embellishment.max_interval)
timer.start(random_wait_time)
# 从池中获取一个当前未在播放的播放器
func _get_available_embellishment_player() -> AudioStreamPlayer:
for player in _embellishment_players:
if not player.playing:
return player
# 如果所有播放器都在忙可以考虑返回null或者动态创建新的播放器不推荐可能导致节点泄漏
printerr("VibeManager: No available embellishment player in the pool.")
return null