多轮审查和修复

This commit is contained in:
2026-05-12 15:34:08 +08:00
parent f55d2a57c3
commit ebbbb7332e
805 changed files with 838724 additions and 1905 deletions

View File

@@ -22,8 +22,22 @@ namespace BaseGames.Audio
[SerializeField] private AudioSource _bgmSourceB;
[Header("SFX Pool建议 6 个,均路由到 SFX MixerGroup")]
[Tooltip("轮转池大小:同帧触发数超过此值时最旧的音效会被打断。建议 6~8 个。")]
[SerializeField] private AudioSource[] _sfxSources;
[Header("Audio ConfigBGM 映射)")]
[SerializeField] private AudioConfigSO _audioConfig;
[Header("SFX 注册表key → AudioEventSO")]
[SerializeField] private AudioEventEntry[] _sfxRegistry;
[System.Serializable]
public struct AudioEventEntry
{
public string Key;
public AudioEventSO Event;
}
[Header("Event Channels - Subscribe")]
[SerializeField] private VoidEventChannelSO _onPlayerDied;
@@ -31,49 +45,61 @@ namespace BaseGames.Audio
private AudioSource _inactiveBGMSource;
private Coroutine _crossfadeCoroutine;
private int _sfxRoundRobin;
// ── 遗留单例(已废弃;新代码请使用 ServiceLocator.Get<IAudioService>())────────────
[System.Obsolete("Use ServiceLocator.Get<IAudioService>() instead.")]
public static AudioManager Instance { get; private set; }
private Dictionary<string, AudioEventSO> _sfxLookup;
private readonly CompositeDisposable _subs = new();
private void Awake()
{
#pragma warning disable CS0618
if (Instance != null) { Destroy(gameObject); return; }
Instance = this;
#pragma warning restore CS0618
if (ServiceLocator.GetOrDefault<IAudioService>() != null) { Destroy(gameObject); return; }
Debug.Assert(_audioConfig != null, "[AudioManager] _audioConfig 未赋值,请在 Inspector 中指定 AudioConfigSO。", this);
_activeBGMSource = _bgmSourceA;
_inactiveBGMSource = _bgmSourceB;
// ServiceLocator 注册(覆盖 GameServiceRegistrar 的 NullAudioService 兜底)
ServiceLocator.Register<IAudioService>(this);
BuildSFXLookup();
Initialize();
}
private void OnEnable()
{
if (_onPlayerDied != null)
_onPlayerDied.OnEventRaised += HandlePlayerDied;
_onPlayerDied?.Subscribe(HandlePlayerDied).AddTo(_subs);
}
private void OnDisable()
{
if (_onPlayerDied != null)
_onPlayerDied.OnEventRaised -= HandlePlayerDied;
_subs.Clear();
}
// ── IAudioService string-key APIPhase 2 接入 AudioEventSO 后完整实现)─────────────
/// <summary>
/// 按 Addressable key 播放 BGM。Phase 2 接入 AudioEventSO 前为占位警告。
/// </summary>
public void PlayBGM(string key)
=> Debug.LogWarning($"[AudioManager] PlayBGM(key) 尚未接入 AudioEventSOPhase 2。key={key}");
private void OnDestroy()
{
ServiceLocator.Unregister<IAudioService>(this);
}
/// <summary>
/// 按 Addressable key 播放 SFX。Phase 2 接入 AudioEventSO 前为占位警告。
/// </summary>
// ── IAudioService string-key API ────────────────────────────────────────────
/// <summary>按 Zone/Boss key 查 AudioConfigSO 播放 BGM。</summary>
public void PlayBGM(string key)
{
var clip = _audioConfig.GetZoneBGM(key) ?? _audioConfig.GetBossBGM(key);
if (clip == null)
{
Debug.LogWarning($"[AudioManager] BGM key '{key}' 在 AudioConfigSO 中未找到。");
return;
}
PlayBGM(clip);
}
/// <summary>按 key 查 SFX 注册表播放 AudioEventSO。</summary>
public void PlaySFX(string key)
=> Debug.LogWarning($"[AudioManager] PlaySFX(key) 尚未接入 AudioEventSOPhase 2。key={key}");
{
if (_sfxLookup != null && _sfxLookup.TryGetValue(key, out var evt))
{
evt?.PlayOneShot(NextSFXSource());
return;
}
Debug.LogWarning($"[AudioManager] SFX key '{key}' 未在注册表中找到。");
}
// ── 音量控制 ─────────────────────────────────────────────────────────────
/// <summary>
@@ -83,10 +109,15 @@ namespace BaseGames.Audio
public void SetVolume(string exposedParam, float linear)
=> _mixer.SetFloat(exposedParam, LinearToDecibel(linear));
/// <summary>读取 GlobalSettings 并应用所有音量初始值。</summary>
/// <summary>读取 SettingsManager 已加载的设置数据并应用四路音量到 AudioMixer。</summary>
public void Initialize()
{
// TODO: 从 SettingsManager / PlayerPrefs 读取保存的音量值并应用
var settings = ServiceLocator.GetOrDefault<ISettingsService>();
GlobalSettingsData data = settings?.Current ?? new GlobalSettingsData();
SetVolume(AudioMixerKeys.Master, data.MasterVolume);
SetVolume(AudioMixerKeys.BGM, data.BGMVolume);
SetVolume(AudioMixerKeys.SFX, data.SFXVolume);
SetVolume(AudioMixerKeys.Ambient, data.AmbientVolume);
}
// ── BGM ──────────────────────────────────────────────────────────────────
@@ -113,6 +144,7 @@ namespace BaseGames.Audio
{
if (clip == null) return;
var src = NextSFXSource();
if (src == null) return;
src.volume = volumeScale;
src.PlayOneShot(clip);
}
@@ -138,9 +170,22 @@ namespace BaseGames.Audio
TransitionToSnapshot("Dead", 1.5f);
}
private void BuildSFXLookup()
{
_sfxLookup = new Dictionary<string, AudioEventSO>(_sfxRegistry?.Length ?? 0);
if (_sfxRegistry == null) return;
foreach (var entry in _sfxRegistry)
if (!string.IsNullOrEmpty(entry.Key) && entry.Event != null)
_sfxLookup[entry.Key] = entry.Event;
}
private AudioSource NextSFXSource()
{
if (_sfxSources == null || _sfxSources.Length == 0) return _bgmSourceA;
if (_sfxSources == null || _sfxSources.Length == 0)
{
Debug.LogError("[AudioManager] SFX Source 池为空,请在 Inspector 中为 _sfxSources 赋值。");
return null;
}
return _sfxSources[_sfxRoundRobin++ % _sfxSources.Length];
}