167 lines
5.2 KiB
GDScript
167 lines
5.2 KiB
GDScript
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
|