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 = 16; [Title("오디오 믹서")] [SerializeField] private AudioMixer audioMixer; [SerializeField] private AudioMixerGroup masterMixerGroup; [SerializeField] private AudioMixerGroup bgmMixerGroup; [SerializeField] private AudioMixerGroup sfxMixerGroup; private Dictionary bgmDictionary; private Dictionary sfxDictionary; private AudioSource bgmAudioSource; private Dictionary sfxPitchDictionary; protected override void OnAwake() { InitDictionary(); InitComponent(); SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { StopBgm(); StopSfxAll(); } private void InitDictionary() { 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); } } private void InitComponent() { 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, float? duration = null) { if (sfxDictionary.TryGetValue(sfxName, out var value)) { var availableSfxAudioSource = GetAvailableSfxAudioSource(); availableSfxAudioSource.clip = value; sfxPitchDictionary[availableSfxAudioSource] = duration.HasValue ? value.length / duration.Value : 1f; availableSfxAudioSource.pitch = sfxPitchDictionary[availableSfxAudioSource] * Time.timeScale; availableSfxAudioSource.Play(); } 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; } public void SetMasterVolume(float volume) { audioMixer.SetFloat("Master", volume); } public void SetBgmVolume(float volume) { audioMixer.SetFloat("Bgm", volume); } public void SetSfxVolume(float volume) { audioMixer.SetFloat("Sfx", volume); } public void SetPitchSfxAll(float pitch) { foreach (var element in sfxPitchDictionary) { element.Key.pitch = element.Value * pitch; } } } }