using UnityEngine.Audio; using UnityEngine; using System.Collections; using System.Collections.Generic; public class MANAGER_Music : MonoBehaviour { public static MANAGER_Music Instance; [Header("Main Settings")] [Range(0f, 1f)] [SerializeField] private float maxVolume = 0.5f; [SerializeField] private float fadeDuration = 1.5f; [Tooltip("Настрой кривую: 0,0 -> 1,1. Плавный выход в начале и конце сделает переход естественнее.")] [SerializeField] private AnimationCurve fadeCurve = AnimationCurve.Linear(0, 0, 1, 1); private AudioSource sourceA; private AudioSource sourceB; private AudioSource activeSource; private Coroutine fadeCoroutine; [Header("Mixer Settings")] [SerializeField] private AudioMixerGroup musicGroup; private Dictionary savedPlaybackTimes = new Dictionary(); void Awake() { if (Instance == null) { Instance = this; SetupSources(); } else { Destroy(gameObject); } } private void SetupSources() { sourceA = gameObject.AddComponent(); sourceB = gameObject.AddComponent(); if (musicGroup != null) { sourceA.outputAudioMixerGroup = musicGroup; sourceB.outputAudioMixerGroup = musicGroup; } sourceA.loop = sourceB.loop = true; sourceA.playOnAwake = sourceB.playOnAwake = false; activeSource = sourceA; activeSource.volume = 0; } public void SwitchMusic(AudioClip newClip) { if (activeSource.clip == newClip) return; AudioSource nextSource = (activeSource == sourceA) ? sourceB : sourceA; if (fadeCoroutine != null) StopCoroutine(fadeCoroutine); fadeCoroutine = StartCoroutine(FadeSequence(nextSource, newClip)); } private IEnumerator FadeSequence(AudioSource nextSource, AudioClip newClip) { float t = 0; float startVol = activeSource.volume; if (newClip != null) { nextSource.clip = newClip; if (savedPlaybackTimes.TryGetValue(newClip, out float savedTime)) { nextSource.time = savedTime; } else { nextSource.time = 0f; } nextSource.Play(); } while (t < fadeDuration) { t += Time.deltaTime; float progress = t / fadeDuration; float curveValue = fadeCurve.Evaluate(progress); activeSource.volume = Mathf.Lerp(startVol, 0, curveValue); if (newClip != null) nextSource.volume = Mathf.Lerp(0, maxVolume, curveValue); yield return null; } if (activeSource.clip != null) { savedPlaybackTimes[activeSource.clip] = activeSource.time; } activeSource.Stop(); activeSource.volume = 0; activeSource = nextSource; activeSource.volume = maxVolume; fadeCoroutine = null; } public void SetVolume(float volume) { maxVolume = Mathf.Clamp01(volume); if (activeSource != null) activeSource.volume = maxVolume; } }