Files
zeling_v2/Assets/Scripts/Audio/BGMController.cs
2026-05-13 09:19:54 +08:00

116 lines
4.3 KiB
C#
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.
using System.Collections;
using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
namespace BaseGames.Audio
{
/// <summary>BGM 状态机内部状态。</summary>
public enum MusicState
{
Exploration, // 默认:区域探索 BGM
Boss, // Boss 战Boss 主题 BGM
Victory, // Boss 击败后短暂胜利音乐
None, // 过场/死亡/主菜单时由 BGMController 直接切换
}
/// <summary>
/// BGM 控制器:订阅世界/Boss/游戏状态事件,指挥 AudioManager 切换 BGM 和快照。
/// 挂在 Persistent 场景 [AudioManager] 子对象上。
/// </summary>
public class BGMController : MonoBehaviour
{
[SerializeField] private AudioManager _audioManager;
[SerializeField] private AudioConfigSO _config;
[Header("Event Channels - Subscribe")]
[SerializeField] private GameStateEventChannelSO _onGameStateChanged;
[SerializeField] private BoolEventChannelSO _onBossFightToggled; // true=开始, false=结束
[SerializeField] private StringEventChannelSO _onRegionEntered;
private MusicState _musicState = MusicState.Exploration;
private string _currentRegion = string.Empty;
private readonly CompositeDisposable _subscriptions = new();
private void Awake()
{
Debug.Assert(_config != null, "[BGMController] _config 未赋值,请在 Inspector 中指定 AudioConfigSO。", this);
}
private void OnEnable()
{
_onBossFightToggled?.Subscribe(OnBossFightToggled).AddTo(_subscriptions);
_onRegionEntered?.Subscribe(OnRegionEntered).AddTo(_subscriptions);
_onGameStateChanged?.Subscribe(HandleStateChanged).AddTo(_subscriptions);
}
private void OnDisable()
{
_subscriptions.Clear();
}
private void OnBossFightToggled(bool started)
{
if (started)
{
_musicState = MusicState.Boss;
var clip = _config.GetBossBGM(_currentRegion);
if (clip == null)
{
Debug.LogWarning($"[BGMController] 区域 '{_currentRegion}' 未配置 Boss BGM将保持当前音乐。", this);
}
else
{
_audioManager.PlayBGM(clip, fadeOutDur: 1f, fadeInDur: 0.5f);
}
_audioManager.TransitionToSnapshot("BossFight", 0.5f);
}
else
{
StartCoroutine(PlayVictoryThenRestore());
}
}
private IEnumerator PlayVictoryThenRestore()
{
_musicState = MusicState.Victory;
_audioManager.PlayBGM(_config.VictoryStingBGM,
fadeOutDur: 0.3f, fadeInDur: 0.1f);
float dur = _config.VictoryStingDuration;
yield return new WaitForSecondsRealtime(dur);
_musicState = MusicState.Exploration;
OnRegionEntered(_currentRegion);
_audioManager.TransitionToSnapshot("Default", 1.0f);
}
private void OnRegionEntered(string regionId)
{
if (regionId == _currentRegion) return;
_currentRegion = regionId;
if (_musicState == MusicState.Exploration)
{
var clip = _config.GetZoneBGM(regionId);
if (clip == null)
{
Debug.LogWarning($"[BGMController] 区域 '{regionId}' 未配置 BGM将保持当前音乐。", this);
return;
}
_audioManager.PlayBGM(clip, fadeOutDur: 1f, fadeInDur: 1f);
}
}
private void HandleStateChanged(GameStateId state)
{
if (state == GameStates.MainMenu)
_audioManager.PlayBGM(_config.MainMenuBGM,
fadeOutDur: 0.5f, fadeInDur: 1.0f);
else if (state == GameStates.Paused)
_audioManager.TransitionToSnapshot("Paused", 0.2f);
else if (state == GameStates.Dead)
_audioManager.TransitionToSnapshot("Dead", 1.5f);
else if (state == GameStates.Gameplay)
_audioManager.TransitionToSnapshot("Default", 0.3f);
}
}
}