using System.Collections; using System.Collections.Generic; using UnityEngine; namespace OCES.Audio { /// /// 环境音通道播放器。 /// 与 MusicChannelPlayer 逻辑相同,但使用 AmbienceTransition 表,不涉及节拍对齐。 /// class AmbienceChannelPlayer { readonly AmbienceTransitionConfig m_transitionConfig; readonly MonoBehaviour m_coroutineHost; readonly ChannelFader m_fader; readonly List m_transitionCandidates = new(); ContainerPlayHandle m_currentHandle; Coroutine m_transitionCoroutine; Coroutine m_currentFadeOutCoroutine; Coroutine m_currentFadeInCoroutine; uint m_currentContainerId; internal AmbienceChannelPlayer( AmbienceTransitionConfig transitionConfig, LongAudioContainerPlayer player, MonoBehaviour coroutineHost) { this.m_transitionConfig = transitionConfig; this.m_coroutineHost = coroutineHost; this.m_fader = new ChannelFader(player, coroutineHost); } // ───────────────────────────────────────────── // 公开接口 // ───────────────────────────────────────────── internal void SwitchTo(uint newContainerId) { if (newContainerId == this.m_currentContainerId && this.m_currentHandle != null) return; AmbienceTransition transition = ResolveTransition((int)this.m_currentContainerId, (int)newContainerId); 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(int sourceContainerId, int destinationContainerId) { this.m_transitionCandidates.Clear(); foreach (AmbienceTransition transition in this.m_transitionConfig.AmbienceTransitionList()) { bool sourceMatch = transition.SourceContainerID == sourceContainerId || transition.SourceContainerID < 0; bool destMatch = transition.DestinationContainerID == destinationContainerId || transition.DestinationContainerID < 0; if (sourceMatch && destMatch) { this.m_transitionCandidates.Add(transition); } } if (this.m_transitionCandidates.Count == 0) return this.m_transitionConfig.QueryById(1); AmbienceTransition best = this.m_transitionCandidates[0]; for (int i = 1; i < this.m_transitionCandidates.Count; i++) { if (this.m_transitionCandidates[i].Id > best.Id) best = this.m_transitionCandidates[i]; } return best; } } }