using System.Collections; using System.Collections.Generic; using UnityEngine; namespace GameFramework { /// /// 音频片段数据,可挂到 ScriptableObject 或直接 SerializeField。 /// [System.Serializable] public class AudioData { public AudioClip audioClip; [Range(0f, 1f)] public float volume = 1f; } /// /// 全局音频管理器(持久单例)。 /// 管理 BGM(背景音乐,循环)和 SFX(音效,一次性)。 /// 音量通过 PlayerPrefs 持久化。 /// public class AudioManager : PersistentSingleton { const string PREF_BGM_VOLUME = "AudioManager_BGMVolume"; const string PREF_SFX_VOLUME = "AudioManager_SFXVolume"; AudioSource bgmPlayer; // 背景音乐播放器 AudioSource sfxPlayer; // 音效播放器 float bgmVolume = 1f; float sfxVolume = 1f; public float BGMVolume => bgmVolume; public float SFXVolume => sfxVolume; protected override void Awake() { base.Awake(); // 如果是重复实例,base.Awake 已调用 Destroy,这里直接返回 if (Instance != this) return; // 创建两个 AudioSource bgmPlayer = gameObject.AddComponent(); bgmPlayer.loop = true; bgmPlayer.playOnAwake = false; sfxPlayer = gameObject.AddComponent(); sfxPlayer.loop = false; sfxPlayer.playOnAwake = false; // 读取持久化音量 bgmVolume = PlayerPrefs.GetFloat(PREF_BGM_VOLUME, 1f); sfxVolume = PlayerPrefs.GetFloat(PREF_SFX_VOLUME, 1f); bgmPlayer.volume = bgmVolume; sfxPlayer.volume = sfxVolume; } #region BGM /// /// 播放背景音乐(循环)。 /// public void PlayBGM(AudioClip clip, bool restart = false) { if (clip == null) return; if (bgmPlayer.isPlaying && bgmPlayer.clip == clip && !restart) return; bgmPlayer.clip = clip; bgmPlayer.volume = bgmVolume; bgmPlayer.Play(); } public void StopBGM() { if (bgmPlayer.isPlaying) bgmPlayer.Stop(); } public void PauseBGM() => bgmPlayer.Pause(); public void UnpauseBGM() => bgmPlayer.UnPause(); public void SetBGMVolume(float volume) { bgmVolume = Mathf.Clamp01(volume); bgmPlayer.volume = bgmVolume; PlayerPrefs.SetFloat(PREF_BGM_VOLUME, bgmVolume); PlayerPrefs.Save(); } #endregion #region SFX /// /// 播放单个音效。 /// public void PlaySFX(AudioData data) { if (data == null || data.audioClip == null) return; // sfxPlayer.volume 已在 Awake 中设为 sfxVolume, // PlayOneShot 的 volumeScale 再乘以 data.volume, // 最终音量 = sfxVolume * data.volume sfxPlayer.PlayOneShot(data.audioClip, data.volume); } /// /// 从列表中随机播放一个音效。 /// public void PlayRandomSFX(AudioData data, List variants = null) { if (variants != null && variants.Count > 0) { PlaySFX(variants[Random.Range(0, variants.Count)]); return; } PlaySFX(data); } public void SetSFXVolume(float volume) { sfxVolume = Mathf.Clamp01(volume); PlayerPrefs.SetFloat(PREF_SFX_VOLUME, sfxVolume); PlayerPrefs.Save(); } #endregion } }