using System.Collections; using UnityEngine; using BaseGames.Core; using BaseGames.Core.Events; namespace BaseGames.Audio { /// BGM 状态机内部状态。 public enum MusicState { Exploration, // 默认:区域探索 BGM Boss, // Boss 战:Boss 主题 BGM Victory, // Boss 击败后短暂胜利音乐 None, // 过场/死亡/主菜单时由 BGMController 直接切换 } /// /// BGM 控制器:订阅世界/Boss/游戏状态事件,指挥 AudioManager 切换 BGM 和快照。 /// 挂在 Persistent 场景 [AudioManager] 子对象上。 /// 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); } } }