using System; using System.Collections; using NaughtyAttributes; using UnityEngine; namespace EscapeRoomEngine.Engine.Runtime.Environment { [RequireComponent(typeof(AudioSource))] public class AmbienceAudio : MonoBehaviour { public static AmbienceAudio Instance { get; private set; } public float fadeDuration = 0.5f; public AmbienceClip initialAmbience; [BoxGroup("Internal")] [SerializeField] private AudioSource[] sources; private AudioSource CurrentSource => sources[currentSource]; private AudioSource OtherSource => sources[(currentSource + 1) % 2]; private int currentSource; private readonly Coroutine[] _activeFades = new Coroutine[2]; // the indices in these fades do not necessarily correspond to the sources private void Awake() { Instance = this; if (sources.Length != 2) { throw new Exception("There must be two sources."); } if (CurrentSource == OtherSource) { throw new Exception("Current source must be different from other source."); } foreach (var source in sources) { source.loop = true; } } public void StartAmbience() { CrossFadeTo(initialAmbience); } public void CrossFadeTo(AmbienceClip ambience) { // prepare fade source var fadeSource = OtherSource; fadeSource.clip = ambience.audio; fadeSource.Play(); // stop any running fades foreach (var fade in _activeFades) { if (fade != null) { StopCoroutine(fade); } } // start new fades _activeFades[0] = StartCoroutine(Fade(CurrentSource, CurrentSource.volume, 0)); _activeFades[1] = StartCoroutine(Fade(fadeSource, fadeSource.volume, ambience.volume)); // switch current source currentSource = (currentSource + 1) % 2; } private IEnumerator Fade(AudioSource source, float from, float to) { var startTime = Time.time; while (Math.Abs(source.volume - to) > 0.0001f) { source.volume = Mathf.Clamp01(Mathf.Lerp( from, to, (Time.time - startTime) / fadeDuration)); yield return null; } } } }