xiandie/manager/audio_manager/audio_manager.gd

167 lines
5.2 KiB
GDScript3
Raw Normal View History

2024-12-23 01:29:31 +00:00
extends Node
2025-06-18 13:48:59 +00:00
# random players
var sfx_players = [] as Array[AudioStreamPlayer]
var idx = 0
2025-06-18 13:48:59 +00:00
# bgm player
var bgm_dict = {}
2025-06-18 13:48:59 +00:00
# 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)
2025-06-18 13:48:59 +00:00
# 初始化基础播放器
_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)
2024-12-23 01:29:31 +00:00
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)
2025-06-18 13:48:59 +00:00
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:
2025-03-12 10:43:02 +00:00
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)
2025-06-18 13:48:59 +00:00
#### 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