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