From b4415dea4c1d8038d47caaa57311bdae39376562 Mon Sep 17 00:00:00 2001 From: yangbear Date: Wed, 1 Jul 2026 22:35:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=9F=B3=E9=A2=91=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E9=87=8D=E5=86=99=E2=80=94AudioManager?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=85=A8=E9=83=A8=E9=9F=B3=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 AudioManager.cs 挂在 [Managers] 上: - _bgSource: 背景音乐(首页/实验), spatialBlend=0, BgVolume可调 - _sfxSource: 音效(篮球/manCall), Stop()可打断 - _voiceSource: 语音中断播放 替换: - PageController: BGMController→AudioManager.I - OpeningFlowController: PlayClipAtPoint→AudioManager.I.PlayBasketball/ManCallSfx - 删除 BGMController.cs - 删除旧 AudioManager.cs(Assets/Scripts/Audio/旧版) --- .../Animation/OpeningFlowController.cs | 4 +- Assets/Scripts/Audio/AudioManager.cs | 132 +++++++++--------- Assets/Scripts/Audio/BGMController.cs | 54 ------- Assets/Scripts/Audio/BGMController.cs.meta | 11 -- Assets/Scripts/UI/PageController.cs | 8 +- 5 files changed, 75 insertions(+), 134 deletions(-) delete mode 100644 Assets/Scripts/Audio/BGMController.cs delete mode 100644 Assets/Scripts/Audio/BGMController.cs.meta diff --git a/Assets/Scripts/Animation/OpeningFlowController.cs b/Assets/Scripts/Animation/OpeningFlowController.cs index 7856024..a63f1b3 100644 --- a/Assets/Scripts/Animation/OpeningFlowController.cs +++ b/Assets/Scripts/Animation/OpeningFlowController.cs @@ -127,7 +127,7 @@ public class OpeningFlowController : MonoBehaviour // Step 2: Shoot + 篮球音效 Debug.Log("[OpeningFlow] Step2: Shoot 开始"); - if (_basketballClip != null) AudioSource.PlayClipAtPoint(_basketballClip, transform.position); + if (AudioManager.I != null) AudioManager.I.PlayBasketballSfx(); if (_manAnimator != null) { _manAnimator.Play("Shoot", 0, 0f); Debug.Log("[OpeningFlow] Shoot Play 已触发"); } yield return new WaitForSeconds(3.15f); Debug.Log("[OpeningFlow] Step2: Shoot 结束"); @@ -136,7 +136,7 @@ public class OpeningFlowController : MonoBehaviour Debug.Log("[OpeningFlow] Step3: manfull 开始"); if (_manAnimator != null) { _manAnimator.Play("manfull", 0, 0f); } yield return new WaitForSeconds(2.1f); - if (_manCallClip != null) AudioSource.PlayClipAtPoint(_manCallClip, transform.position); + if (AudioManager.I != null) AudioManager.I.PlayManCallSfx(); Debug.Log("[OpeningFlow] manfull 播放完成, 停留 2s"); yield return new WaitForSeconds(2f); diff --git a/Assets/Scripts/Audio/AudioManager.cs b/Assets/Scripts/Audio/AudioManager.cs index 1f71e74..a8bef54 100644 --- a/Assets/Scripts/Audio/AudioManager.cs +++ b/Assets/Scripts/Audio/AudioManager.cs @@ -1,92 +1,98 @@ using UnityEngine; /// -/// 音频管理器:管理背景音乐和步骤语音解说。 -/// 挂在场景 GameObject 上,通过 AudioSource 组件播放。 +/// 统一音频管理器——挂在 [Managers] 上,管理所有背景音乐/音效/语音。 /// -[RequireComponent(typeof(AudioSource))] public class AudioManager : MonoBehaviour { - public static AudioManager Instance { get; private set; } - - [Header("音频源")] - [SerializeField] private AudioSource _bgmSource; - [SerializeField] private AudioSource _voiceSource; + public static AudioManager I { get; private set; } [Header("背景音乐")] - public AudioClip BGMClip; - [Range(0f, 1f)] public float BGMVolume = 0.3f; + [SerializeField] private AudioClip _homeBg; + [SerializeField] private AudioClip _experimentBg; + [Range(0,1)] public float BgVolume = 0.5f; - private void Awake() + [Header("音效")] + [SerializeField] private AudioClip _basketballSfx; + [SerializeField] private AudioClip _manCallSfx; + + private AudioSource _bgSource; + private AudioSource _sfxSource; + private AudioSource _voiceSource; + + void Awake() { - if (Instance != null) { Destroy(gameObject); return; } - Instance = this; - DontDestroyOnLoad(gameObject); + I = this; + _bgSource = gameObject.AddComponent(); + _bgSource.loop = true; + _bgSource.playOnAwake = false; + _bgSource.spatialBlend = 0f; - if (_bgmSource == null) _bgmSource = GetComponent(); - if (_voiceSource == null) - { - _voiceSource = gameObject.AddComponent(); - _voiceSource.playOnAwake = false; - _voiceSource.loop = false; - } + _sfxSource = gameObject.AddComponent(); + _sfxSource.playOnAwake = false; + _sfxSource.spatialBlend = 0f; + + _voiceSource = gameObject.AddComponent(); + _voiceSource.playOnAwake = false; + _voiceSource.spatialBlend = 0f; + +#if UNITY_EDITOR + if (_homeBg == null) _homeBg = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/homeBackgroundMusic.mp3"); + if (_experimentBg == null) _experimentBg = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/backgroundMusic.mp3"); + if (_basketballSfx == null) _basketballSfx = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/start/basketballSound.wav"); + if (_manCallSfx == null) _manCallSfx = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/start/mancall.wav"); +#endif + Debug.Log($"[AudioManager] 就绪 homeBg={_homeBg!=null} expBg={_experimentBg!=null} sfx={_basketballSfx!=null}/{_manCallSfx!=null}"); } - private void Start() + // ────── 背景音乐 ────── + public void PlayHomeBg() { - PlayBGM(); + if (_homeBg == null) return; + _bgSource.clip = _homeBg; + _bgSource.volume = BgVolume; + _bgSource.Play(); + Debug.Log($"[AudioManager] 首页bg isPlaying={_bgSource.isPlaying}"); } - public void PlayBGM() + public void PlayExperimentBg() { - if (_bgmSource == null || BGMClip == null) return; - _bgmSource.clip = BGMClip; - _bgmSource.volume = BGMVolume; - _bgmSource.loop = true; - _bgmSource.Play(); + if (_experimentBg == null) return; + _bgSource.clip = _experimentBg; + _bgSource.volume = BgVolume; + _bgSource.Play(); + Debug.Log($"[AudioManager] 实验bg isPlaying={_bgSource.isPlaying}"); } - public void StopBGM() + public void StopBgMusic() { - if (_bgmSource != null) _bgmSource.Stop(); + _bgSource.Stop(); + Debug.Log("[AudioManager] 停止bg"); } - /// 播放一步语音解说,自动打断前一条 - public void PlayVoice(AudioClip clip, float volume = 1f) + // ────── 音效(可打断) ────── + public void PlaySfx(AudioClip clip) { - if (_voiceSource == null || clip == null) return; + if (clip == null) return; + _sfxSource.Stop(); + _sfxSource.clip = clip; + _sfxSource.Play(); + } + + public void StopSfx() { _sfxSource.Stop(); } + + public void PlayBasketballSfx() => PlaySfx(_basketballSfx); + public void PlayManCallSfx() => PlaySfx(_manCallSfx); + + // ────── 语音(可打断) ────── + public void PlayVoice(AudioClip clip) + { + if (clip == null) return; _voiceSource.Stop(); _voiceSource.clip = clip; - _voiceSource.volume = volume; _voiceSource.Play(); + Debug.Log($"[AudioManager] 播放语音: {clip.name}"); } - /// 停止语音 - public void StopVoice() - { - if (_voiceSource != null) _voiceSource.Stop(); - } - - /// 按文件名从 StreamingAssets 加载并播放语音 - public void PlayVoiceFromFile(string fileName) - { - if (string.IsNullOrEmpty(fileName)) return; - StartCoroutine(LoadAndPlayVoice(fileName)); - } - - private System.Collections.IEnumerator LoadAndPlayVoice(string fileName) - { - string path = System.IO.Path.Combine(Application.streamingAssetsPath, "Voice", fileName); - using var www = UnityEngine.Networking.UnityWebRequestMultimedia.GetAudioClip(path, AudioType.WAV); - yield return www.SendWebRequest(); - if (www.result == UnityEngine.Networking.UnityWebRequest.Result.Success) - { - var clip = UnityEngine.Networking.DownloadHandlerAudioClip.GetContent(www); - PlayVoice(clip); - } - else - { - Debug.LogWarning($"AudioManager: 加载语音失败 {path}"); - } - } + public void StopVoice() { _voiceSource.Stop(); } } diff --git a/Assets/Scripts/Audio/BGMController.cs b/Assets/Scripts/Audio/BGMController.cs deleted file mode 100644 index 30c1b8e..0000000 --- a/Assets/Scripts/Audio/BGMController.cs +++ /dev/null @@ -1,54 +0,0 @@ -using UnityEngine; - -/// -/// 背景音乐控制器——挂在 [Managers] 上,独立于 PageController。 -/// 静态方法供外部调用。 -/// -public class BGMController : MonoBehaviour -{ - [SerializeField] private AudioClip _homeBgClip; - [SerializeField] private AudioClip _experimentBgClip; - private AudioSource _bgSource; - - private static BGMController _instance; - - void Awake() - { - _instance = this; - _bgSource = gameObject.AddComponent(); - _bgSource.loop = true; - _bgSource.playOnAwake = false; - _bgSource.spatialBlend = 0f; - _bgSource.volume = 0.5f; - -#if UNITY_EDITOR - if (_homeBgClip == null) _homeBgClip = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/homeBackgroundMusic.mp3"); - if (_experimentBgClip == null) _experimentBgClip = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/backgroundMusic.mp3"); -#endif - Debug.Log($"[BGMController] 就绪 homeBg={(_homeBgClip!=null)} expBg={(_experimentBgClip!=null)}"); - } - - public static void PlayHomeBg() - { - if (_instance == null || _instance._homeBgClip == null) { Debug.LogWarning("[BGMController] PlayHomeBg 失败"); return; } - _instance._bgSource.clip = _instance._homeBgClip; - _instance._bgSource.volume = 0.5f; - _instance._bgSource.Play(); - Debug.Log($"[BGMController] 播放首页bg isPlaying={_instance._bgSource.isPlaying}"); - } - - public static void PlayExperimentBg() - { - if (_instance == null || _instance._experimentBgClip == null) { Debug.LogWarning("[BGMController] PlayExperimentBg 失败"); return; } - _instance._bgSource.clip = _instance._experimentBgClip; - _instance._bgSource.volume = 0.5f; - _instance._bgSource.Play(); - Debug.Log($"[BGMController] 播放实验bg isPlaying={_instance._bgSource.isPlaying}"); - } - - public static void StopBgMusic() - { - if (_instance != null) _instance._bgSource.Stop(); - Debug.Log("[BGMController] 停止bg"); - } -} diff --git a/Assets/Scripts/Audio/BGMController.cs.meta b/Assets/Scripts/Audio/BGMController.cs.meta deleted file mode 100644 index 5b1007b..0000000 --- a/Assets/Scripts/Audio/BGMController.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d5a0e43c7217447f9b4be5e2434520e4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/UI/PageController.cs b/Assets/Scripts/UI/PageController.cs index 03ebc33..ef00963 100644 --- a/Assets/Scripts/UI/PageController.cs +++ b/Assets/Scripts/UI/PageController.cs @@ -121,8 +121,8 @@ public class PageController : MonoBehaviour if (_uiManager != null) _uiManager.enabled = (page == Page.Experiment); - if (page == Page.Home) BGMController.PlayHomeBg(); // 背景音乐: 首页播 homeBg, 选固定方式时停, 实验启动时播 experimentBg - if (page == Page.Home) BGMController.PlayHomeBg(); + if (page == Page.Home) AudioManager.I.PlayHomeBg(); // 背景音乐: 首页播 homeBg, 选固定方式时停, 实验启动时播 experimentBg + if (page == Page.Home) AudioManager.I.PlayHomeBg(); Debug.Log($"PageController(编辑器预览): 切换到 [{page}]"); } #endif @@ -224,7 +224,7 @@ public class PageController : MonoBehaviour Debug.Log($"PageController: GameManager 已设置 Mode=[{gm.CurrentMode}] Fixation=[{gm.CurrentFixationMethod}]"); // 隐藏所有UI面板,准备播放片头动画 - BGMController.StopBgMusic(); + AudioManager.I.StopBgMusic(); HideAllPages(); // 找到 OpeningFlowController 播放片头动画 @@ -267,7 +267,7 @@ public class PageController : MonoBehaviour { Debug.Log("PageController: [ActivateExperimentObjects] 显示实验物件"); - BGMController.PlayExperimentBg(); + AudioManager.I.PlayExperimentBg(); var allObjects = FindObjectsOfType(true); foreach (var go in allObjects)