Files
Cielonos/Assets/Scripts/SLSUtilities/WwiseAssistance/BackgroundMusicManager.cs
SoulliesOfficial 6d7ebc5825 Passion & UI
2026-06-12 17:11:39 -04:00

147 lines
5.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using AK.Wwise;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.SceneManagement;
using Event = AK.Wwise.Event;
namespace SLSUtilities.WwiseAssistance
{
/// <summary>
/// 背景音乐管理器。
/// <para>
/// 随 <see cref="AudioManager"/> 持久化DontDestroyOnLoad跨场景保持唯一实例。
/// 通过 Wwise Event 播放 / 停止音乐。
/// 淡入由 Wwise Event 自身的 Fade-In 配置控制,
/// 淡出由 <c>ExecuteActionOnPlayingID(Stop, transitionDuration)</c> 实现。
/// </para>
/// </summary>
public class BackgroundMusicManager : SerializedMonoBehaviour
{
// ──────────────────── 常量 ────────────────────
private const int DefaultFadeOutMs = 1000;
private const string LoadingSceneName = "Loading";
// ──────────────────── 序列化字段 ────────────────────
[Title("Wwise")]
[Tooltip("音乐状态名 → Wwise State 映射,播放时自动设置对应 State。")]
public Dictionary<string, State> baseMusicDictionary;
[Required]
[Tooltip("播放 BGM 的 Wwise Event。淡入请在 Wwise Authoring 的该 Event Play 动作上配置 Fade-In。")]
public Event playMusicEvent;
// ──────────────────── 运行时状态 ────────────────────
[Title("Runtime")]
[ShowInInspector, ReadOnly]
public bool isOverridden;
[ShowInInspector, ReadOnly]
private string lastMusicStateName;
/// <summary>当前播放的 Wwise Playing ID。</summary>
private uint currentPlayingID;
/// <summary>是否在等待下一个场景加载后自动重播。</summary>
private bool pendingReplay;
/// <summary> 是否已经开始播放过音乐。用于避免在 Start 前就响应场景加载事件导致的重复播放。</summary>
private bool _isStarted = false;
// ──────────────────── 生命周期 ────────────────────
private void Start()
{
if (_isStarted) return;
_isStarted = true;
PlayMusic("NormalMusic");
}
private void OnEnable() => SceneManager.sceneLoaded += OnSceneLoaded;
private void OnDisable() => SceneManager.sceneLoaded -= OnSceneLoaded;
// ──────────────────── 公开 API ────────────────────
/// <summary>
/// 播放指定状态的背景音乐。淡入效果由 Wwise Event 自身的 Fade-In 配置控制。
/// 被覆盖期间仅记录状态名,不实际播放。
/// </summary>
public void PlayMusic(string musicStateName)
{
lastMusicStateName = musicStateName;
if (isOverridden) return;
StopImmediate();
// 设置 Wwise State 以选择正确的音乐变体
if (baseMusicDictionary.TryGetValue(musicStateName, out var state))
{
state.SetValue();
}
currentPlayingID = playMusicEvent.Post(gameObject);
if (currentPlayingID == AkUnitySoundEngine.AK_INVALID_PLAYING_ID)
{
Debug.LogWarning("[BGM] playMusicEvent.Post 返回了无效的 Playing ID。");
}
}
/// <summary>
/// 立即停止背景音乐(无淡出)。
/// </summary>
public void StopMusic() => StopImmediate();
/// <summary>
/// 带淡出停止当前音乐,并在下一个非 Loading 场景加载后自动重新播放。
/// 用于场景切换前调用。
/// </summary>
public void TransitionToNextScene(int fadeOutMs = DefaultFadeOutMs)
{
pendingReplay = true;
StopWithFade(fadeOutMs);
}
/// <summary>
/// 设置覆盖标记。被覆盖时 <see cref="PlayMusic"/> 仅记录状态名,不实际播放。
/// </summary>
public void SetOverride(bool overridden) => isOverridden = overridden;
// ──────────────────── 内部实现 ────────────────────
private void StopImmediate()
{
if (currentPlayingID == AkUnitySoundEngine.AK_INVALID_PLAYING_ID) return;
AkUnitySoundEngine.ExecuteActionOnPlayingID(
AkActionOnEventType.AkActionOnEventType_Stop,
currentPlayingID, 0,
AkCurveInterpolation.AkCurveInterpolation_Linear);
currentPlayingID = AkUnitySoundEngine.AK_INVALID_PLAYING_ID;
}
private void StopWithFade(int fadeOutMs)
{
if (currentPlayingID == AkUnitySoundEngine.AK_INVALID_PLAYING_ID) return;
AkUnitySoundEngine.ExecuteActionOnPlayingID(
AkActionOnEventType.AkActionOnEventType_Stop,
currentPlayingID, fadeOutMs,
AkCurveInterpolation.AkCurveInterpolation_Linear);
currentPlayingID = AkUnitySoundEngine.AK_INVALID_PLAYING_ID;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (!pendingReplay || scene.name == LoadingSceneName) return;
pendingReplay = false;
PlayMusic(string.IsNullOrEmpty(lastMusicStateName) ? "NormalMusic" : lastMusicStateName);
}
}
}