using System.Collections.Generic; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.Audio; using UnityEngine.SceneManagement; namespace BlueWater.Audios { public class AudioManager : Singleton { [Title("오디오 데이터")] [SerializeField] private BgmDataSo _bgmDataSo; [SerializeField] private SfxDataSo _sfxDataSo; [SerializeField] private int _sfxChannelCount = 32; [Title("오디오 믹서")] [SerializeField] private AudioMixer _audioMixer; [SerializeField] private AudioMixerGroup _masterMixerGroup; [SerializeField] private AudioMixerGroup _bgmMixerGroup; [SerializeField] private AudioMixerGroup _sfxMixerGroup; [Title("중복 사운드 처리")] [SerializeField, Range(0f, 1f)] private float _sfxMinInterval = 0.09f; private Dictionary _bgmDictionary; private Dictionary _sfxDictionary; private AudioSource _bgmAudioSource; private Dictionary _sfxPitchDictionary; private Dictionary _sfxPlayTimeDictionary; protected override void OnAwake() { InitializeDictionary(); InitializeComponents(); SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { StopBgm(); StopSfxAll(); } private void InitializeDictionary() { _bgmDictionary = new Dictionary(_bgmDataSo.BgmDataList.Count); foreach (var element in _bgmDataSo.BgmDataList) { _bgmDictionary.Add(element.BgmName, element.Clip); } _sfxDictionary = new Dictionary(_sfxDataSo.SfxDataList.Count); foreach (var element in _sfxDataSo.SfxDataList) { _sfxDictionary.Add(element.SfxName, element.Clip); } _sfxPlayTimeDictionary = new Dictionary(_sfxDataSo.SfxDataList.Count); } private void InitializeComponents() { _bgmAudioSource = gameObject.AddComponent(); _bgmAudioSource.outputAudioMixerGroup = _bgmMixerGroup; _bgmAudioSource.loop = true; _sfxPitchDictionary = new Dictionary(_sfxChannelCount); for (var i = 0; i < _sfxChannelCount; i++) { var sfxAudioSource = gameObject.AddComponent(); sfxAudioSource.outputAudioMixerGroup = _sfxMixerGroup; sfxAudioSource.loop = false; _sfxPitchDictionary[sfxAudioSource] = sfxAudioSource.pitch; } } public void PlayBgm(string bgmName) { if (_bgmDictionary.TryGetValue(bgmName, out var value)) { _bgmAudioSource.clip = value; _bgmAudioSource.Play(); } else { print("Bgm not found: " + bgmName); } } public void StopBgm() { _bgmAudioSource.Stop(); } public void PlaySfx(string sfxName, bool loop = false, bool ignoreTimeScale = false, float? duration = null) { if (_sfxDictionary.TryGetValue(sfxName, out var value)) { if (_sfxPlayTimeDictionary.TryGetValue(sfxName, out var lastPlayTime)) { if (Time.time - lastPlayTime < _sfxMinInterval) { return; } } var availableSfxAudioSource = GetAvailableSfxAudioSource(); availableSfxAudioSource.clip = value; availableSfxAudioSource.loop = loop; if (ignoreTimeScale) { // Time.timeScale 영향을 받지 않는 효과음 처리 availableSfxAudioSource.pitch = duration.HasValue ? value.length / duration.Value : 1f; } else { // Time.timeScale 적용 _sfxPitchDictionary[availableSfxAudioSource] = duration.HasValue ? value.length / duration.Value : 1f; availableSfxAudioSource.pitch = _sfxPitchDictionary[availableSfxAudioSource] * Time.timeScale; } availableSfxAudioSource.Play(); _sfxPlayTimeDictionary[sfxName] = Time.time; } else { print("Sfx not found: " + sfxName); } } public void StopSfx(string sfxName) { if (_sfxDictionary.TryGetValue(sfxName, out var clip)) { foreach (var element in _sfxPitchDictionary.Keys) { if (element.clip == clip && element.isPlaying) { element.Stop(); } } } else { Debug.LogWarning("Sfx not found: " + sfxName); } } public void StopSfxAll() { foreach (var element in _sfxPitchDictionary.Keys) { if (element.isPlaying) { element.Stop(); } } } private AudioSource GetAvailableSfxAudioSource() { foreach (var element in _sfxPitchDictionary.Keys) { if (!element.isPlaying) { return element; } } // 모든 AudioSource가 사용 중이면 첫 번째 AudioSource를 재사용 //return sfxPitchDictionary.Keys.GetEnumerator().Current; using var enumerator = _sfxPitchDictionary.Keys.GetEnumerator(); enumerator.MoveNext(); return enumerator.Current; } /// /// 0.0001 ~ 1값 /// /// public void SetMasterVolume(float volume) { var newVolume = Mathf.Log10(volume) * 20f; _audioMixer.SetFloat("Master", newVolume); } public void SetBgmVolume(float volume) { var newVolume = Mathf.Log10(volume) * 20f; _audioMixer.SetFloat("Bgm", newVolume); } public void SetSfxVolume(float volume) { var newVolume = Mathf.Log10(volume) * 20f; _audioMixer.SetFloat("Sfx", newVolume); } public void SetPitchSfxAll(float pitch) { foreach (var element in _sfxPitchDictionary) { element.Key.pitch = element.Value * pitch; } } } }