101 lines
4.1 KiB
C#
101 lines
4.1 KiB
C#
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 void OnEnable()
|
||
{
|
||
if (_onBossFightToggled != null) _onBossFightToggled.OnEventRaised += OnBossFightToggled;
|
||
if (_onRegionEntered != null) _onRegionEntered.OnEventRaised += OnRegionEntered;
|
||
if (_onGameStateChanged != null) _onGameStateChanged.OnEventRaised += HandleStateChanged;
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
if (_onBossFightToggled != null) _onBossFightToggled.OnEventRaised -= OnBossFightToggled;
|
||
if (_onRegionEntered != null) _onRegionEntered.OnEventRaised -= OnRegionEntered;
|
||
if (_onGameStateChanged != null) _onGameStateChanged.OnEventRaised -= HandleStateChanged;
|
||
}
|
||
|
||
private void OnBossFightToggled(bool started)
|
||
{
|
||
if (started)
|
||
{
|
||
_musicState = MusicState.Boss;
|
||
var clip = _config != null ? _config.GetBossBGM(_currentRegion) : null;
|
||
_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 != null ? _config.VictoryStingBGM : null,
|
||
fadeOutDur: 0.3f, fadeInDur: 0.1f);
|
||
float dur = _config != null ? _config.VictoryStingDuration : 4f;
|
||
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 != null ? _config.GetZoneBGM(regionId) : null;
|
||
_audioManager.PlayBGM(clip, fadeOutDur: 1f, fadeInDur: 1f);
|
||
}
|
||
}
|
||
|
||
private void HandleStateChanged(GameStateId state)
|
||
{
|
||
// ⚠️ GameStateId 是 struct,不能用 switch;使用 if/else + GameStates 常量
|
||
if (state == GameStates.MainMenu)
|
||
_audioManager.PlayBGM(_config != null ? _config.MainMenuBGM : null,
|
||
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);
|
||
}
|
||
}
|
||
}
|