using System.Collections; using UnityEngine; namespace OCES.Audio { /// /// 环境音通道播放器。 /// 与 MusicChannelPlayer 逻辑相同,但使用 AmbienceTransition 表,不涉及节拍对齐。 /// public class AmbienceChannelPlayer { readonly AmbienceTransitionConfig m_transitionConfig; readonly MonoBehaviour m_coroutineHost; readonly ChannelFader m_fader; ContainerPlayHandle m_currentHandle; Coroutine m_transitionCoroutine; Coroutine m_currentFadeOutCoroutine; Coroutine m_currentFadeInCoroutine; uint m_currentContainerId; public AmbienceChannelPlayer( AmbienceTransitionConfig transitionConfig, MusicContainerPlayer player, MonoBehaviour coroutineHost) { this.m_transitionConfig = transitionConfig; this.m_coroutineHost = coroutineHost; this.m_fader = new ChannelFader(player, coroutineHost); } // ───────────────────────────────────────────── // 公开接口 // ───────────────────────────────────────────── public void SwitchTo(uint newContainerId, uint fromPathId, uint toPathId) { if (newContainerId == this.m_currentContainerId && this.m_currentHandle != null) return; AmbienceTransition transition = ResolveTransition(fromPathId, toPathId); if (this.m_transitionCoroutine != null) this.m_coroutineHost.StopCoroutine(this.m_transitionCoroutine); this.m_transitionCoroutine = this.m_coroutineHost.StartCoroutine( DoTransition(newContainerId, transition)); } public void Stop() { if (this.m_transitionCoroutine != null) this.m_coroutineHost.StopCoroutine(this.m_transitionCoroutine); this.m_fader.StopCurrent(); } // ───────────────────────────────────────────── // Transition 流程(无节拍对齐) // ───────────────────────────────────────────── IEnumerator DoTransition(uint newContainerId, AmbienceTransition transition) { if (newContainerId == this.m_fader.CurrentContainerId && this.m_fader.CurrentHandle != null) yield break; // 如果等待期间被切回来了,就不淡变了 if (this.m_currentFadeInCoroutine != null) { this.m_coroutineHost.StopCoroutine(this.m_currentFadeInCoroutine); this.m_currentFadeInCoroutine = null; } if (this.m_currentFadeOutCoroutine != null) { this.m_coroutineHost.StopCoroutine(this.m_currentFadeOutCoroutine); this.m_currentFadeOutCoroutine = null; } ContainerPlayHandle outgoing = this.m_fader.CurrentHandle; float outgoingVolume = this.m_fader.CurrentVolume; this.m_currentFadeOutCoroutine = this.m_coroutineHost.StartCoroutine( this.m_fader.FadeOutBranch(outgoing, outgoingVolume, transition)); this.m_currentFadeInCoroutine = this.m_coroutineHost.StartCoroutine( this.m_fader.FadeInBranch(newContainerId, transition)); yield return this.m_currentFadeInCoroutine; this.m_currentFadeInCoroutine = null; } // ───────────────────────────────────────────── // 工具 // ───────────────────────────────────────────── AmbienceTransition ResolveTransition(uint fromPathId, uint toPathId) { // 优先精确匹配 uint exactId = fromPathId * 1000 + toPathId; AmbienceTransition exact = this.m_transitionConfig.QueryById(exactId); if (exact != null) return exact; // From 为任意 uint fromWildcard = 999u * 1000 + toPathId; AmbienceTransition fromWild = this.m_transitionConfig.QueryById(fromWildcard); if (fromWild != null) return fromWild; // To 为任意 uint toWildcard = fromPathId * 1000 + 999u; AmbienceTransition toWild = this.m_transitionConfig.QueryById(toWildcard); if (toWild != null) return toWild; // 全通配 const uint allWild = 999u * 1000 + 999u; return this.m_transitionConfig.QueryById(allWild); } } }