using UnityEngine; using UnityEngine.Audio; public class SoundManager : MonoBehaviour { public static SoundManager Instance { get; private set; } [SerializeField] private AudioSource _bgmSource; [SerializeField] private AudioSource _sfxSource; [SerializeField] private AudioMixer _mixer; [Header("SFX")] [SerializeField] private AudioClip SFX_UIHover; private const string BGM_VOLUME_PARAM = "BGMVolume"; private const string SFX_VOLUME_PARAM = "SFXVolume"; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; } private void OnDestroy() { if (Instance == this) Instance = null; } public void PlaySFX(AudioClip clip) { if(_sfxSource == null || clip == null) return; _sfxSource.PlayOneShot(clip); } public void PlayBGM(AudioClip clip) { if (_bgmSource == null || clip == null) return; _bgmSource.clip = clip; _bgmSource.loop = true; _bgmSource.Play(); } public void StopBGM() { if (_bgmSource == null) return; _bgmSource.Stop(); } public async Awaitable CrossfadeBGM(AudioClip next, float duration = 1f) { if (_bgmSource == null || next == null) return; float startVolume = _bgmSource.volume; for (float t = 0f; t < duration; t += Time.deltaTime) { _bgmSource.volume = Mathf.Lerp(startVolume, 0f, t / duration); await Awaitable.NextFrameAsync(); } _bgmSource.Stop(); _bgmSource.clip = next; _bgmSource.loop = true; _bgmSource.Play(); for (float t = 0f; t < duration; t += Time.deltaTime) { _bgmSource.volume = Mathf.Lerp(0f, startVolume, t / duration); await Awaitable.NextFrameAsync(); } _bgmSource.volume = startVolume; } public void SetBGMVolume(float linear) => SetMixerVolume(BGM_VOLUME_PARAM, linear); public void SetSFXVolume(float linear) => SetMixerVolume(SFX_VOLUME_PARAM, linear); private void SetMixerVolume(string parameter, float linear) { if (_mixer == null) return; float db = linear > 0.0001f ? Mathf.Log10(linear) * 20f : -80f; _mixer.SetFloat(parameter, db); } public void SFXPlay_UIHover() { PlaySFX(SFX_UIHover); } }