본문 바로가기

TIL

[ 24.06.12 ] 내일배움캠프 TIL - AudioManager

[ ps ]

 

[ 백준 / C++ ] 5430 : AC (tistory.com)

 

[ Unity ]

 

AudioClip은 Unity에서 사운드 파일을 저장하는 타입이다.

 

AudioSource 컴포넌트는 사운드를 재생하는데 사용된다. AudioClip을 연결하여 사운드를 재생한다.

또한 볼륨 설정, 사운드 반복 재생 등의 다양한 설정을 할 수 있다.

 

AudioListener 컴포넌트는 사운드를 듣기 위해 무조건 필요하고, 보통 MainCamera에 붙어있다.

게임 내에 하나의 컴포넌트만 존재해야 한다.

 

using UnityEngine;

public class AudioManager : Singleton<AudioManager>
{
    public AudioClip backgroundMusic;
    private AudioSource _audioSource;

    void Start()
    {
        _audioSource = gameObject.AddComponent<AudioSource>();
        _audioSource.loop = true;
        PlayBackgroundMusic();
    }

    public void PlayBackgroundMusic()
    {
        if (backgroundMusic != null)
        {
            _audioSource.Stop();
            _audioSource.clip = backgroundMusic;
            _audioSource.Play();
        }
        else
        {
            Debug.LogWarning("[AudioManager] Background music is not set.");
        }
    }

    public void PlaySound(AudioClip clip)
    {
        _audioSource.PlayOneShot(clip);
    }

    public void StopBackgroundMusic()
    {
        _audioSource.Stop();
    }
}
using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;

    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = (T)FindObjectOfType(typeof(T));

                if (instance == null)
                {
                    GameObject singletonObject = new GameObject();
                    instance = singletonObject.AddComponent<T>();
                }
            }
            return _instance;
        }
    }
    
    public void Awake()
    {
	DontDestroyOnLoad(instance);        
    }
}

 

이렇게 싱글톤 패턴의 AudioManager를 작성할 수 있다.

PlaySound 메서드를 통해 순간순간 AudioClip을 재생할 수 있다.

 

만약 이를 오브젝트 풀 패턴으로 작성하고 싶다면 오브젝트를 만들고
이를 통해 AudioClip을 재생하고 재활용하면 된다.

 

using UnityEngine;

public class SoundManager : MonoBehaviour
{
    public static SoundManager instance;

    [SerializeField][Range(0f, 1f)] private float soundEffectVolume;
    [SerializeField][Range(0f, 1f)] private float soundEffectPitchVariance;
    [SerializeField][Range(0f, 1f)] private float musicVolume;

    private AudioSource musicAudioSource;
    public AudioClip musicClip;

    private void Awake()
    {
        instance = this;
        musicAudioSource = GetComponent<AudioSource>();
        musicAudioSource.volume = musicVolume;
        musicAudioSource.loop = true;
    }

    private void Start()
    {
        ChangeBackgroundMusic(musicClip);
    }

    private void ChangeBackgroundMusic(AudioClip musicClip)
    {
        instance.musicAudioSource.Stop();
        instance.musicAudioSource.clip = musicClip;
        instance.musicAudioSource.Play();
    }

    public static void PlayClip(AudioClip clip)
    {
        GameObject obj = GameManager.Instance.ObjectPool.SpawnFromPool("SoundSource");
        obj.SetActive(true);
        SoundSource soundSource = obj.GetComponent<SoundSource>();
        soundSource.Play(clip, instance.soundEffectVolume, instance.soundEffectPitchVariance);
    }
}
using UnityEngine;

public class SoundSource : MonoBehaviour
{
    private AudioSource audioSource;

    public void Play(AudioClip clip, float soundEffectVolume, float soundEffectPitchVariance)
    {
        if(audioSource == null)
            audioSource = GetComponent<AudioSource>();

        CancelInvoke();

        audioSource.clip = clip;
        audioSource.volume = soundEffectVolume;
        audioSource.pitch = 1f + Random.Range(-soundEffectPitchVariance, soundEffectPitchVariance);
        audioSource.Play();

        Invoke("Disable", clip.length + 2);
    }

    public void Disable()
    {
        audioSource.Stop();
        gameObject.SetActive(false);
    }
}
using System.Collections.Generic;
using UnityEngine;

public class ObjectPool : MonoBehaviour
{
    [System.Serializable]
    public class Pool
    {
        public string tag;
        public GameObject prefab;
        public int size;
    }

    public List<Pool> Pools;
    public Dictionary<string, Queue<GameObject>> PoolDictionary;

    private void Awake()
    {
        PoolDictionary = new Dictionary<string, Queue<GameObject>>();
        foreach (var pool in Pools)
        {
            Queue<GameObject> objectPool = new Queue<GameObject>();
            for (int i = 0; i < pool.size; i++)
            {
                GameObject obj = Instantiate(pool.prefab);
                obj.SetActive(false);
                
                objectPool.Enqueue(obj);
            }
            PoolDictionary.Add(pool.tag, objectPool);
        }
    }

    public GameObject SpawnFromPool(string tag)
    {
        if (!PoolDictionary.ContainsKey(tag))
            return null;

        GameObject obj = PoolDictionary[tag].Dequeue();
        PoolDictionary[tag].Enqueue(obj);

        return obj;
    }
}
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;
    
    public ObjectPool ObjectPool { get; private set; }

    private void Awake()
    {
        if(Instance != null) Destroy(gameObject);
        Instance = this;

        ObjectPool = GetComponent<ObjectPool>();
    }
}