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)