[Unity] Audio Manager로 게임 사운드 관리하기

Gee·2025년 2월 27일

팀 프로젝트 진행 중, 처음엔 맡은 아이템에 대한 효과음만 관리해 보려고 Item.cs에서 효과음을 적용해보기 시작.

// 아이템 기본 클래스 (부모 클래스)
public class Item : MonoBehaviour
{
    // +++++ 오디오 관련 +++++
    AudioSource _audioSource;   // 오디오 소스
    public AudioClip itemSound; // 아이템 획득 효과음

    // +++++ 오디오 관련 +++++
    void Awake()
    {
        _audioSource = GetComponent<AudioSource>(); // 오디오 소스 가져오기
    }

    // 플레이어가 아이템을 획득했을 때 실행되는 메서드 (모든 아이템 공통)
    protected virtual void OnCollect(Player player)
    {
        // +++++ 오디오 관련 +++++
        if (_audioSource != null && itemSound != null)
        {
            AudioSource.PlayClipAtPoint(itemSound, transform.position);    // 효과음 재생
            
            // ++제대로 동작 안하는 코드++
            // _audioSource.PlayOneShot(itemSound);
            // Destroy(gameObject, itemSound.length); // 효과음 길이만큼 기다렸다가 삭제 (이렇게 하면 아이템이 바로 안 사라짐..)
        }
        
        Destroy(gameObject); // 아이템 제거
        Debug.Log($"{gameObject.name} 아이템 획득!");
    }
    
    // 충돌 감지. 플레이어와 충돌하면 OnCollect 실행
    private void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.CompareTag("Player")) // "Player" 태그 오브젝트와 충돌했는지 확인
        {
            Player player = collider.GetComponent<Player>();    // 충돌한 오브젝트에서 Player 가져오기
            if (player != null)
            {
                OnCollect(player);    // 아이템 획득 처리
            }
            else
            {
                Debug.LogWarning("플레이어 객체가 없습니다!");
            }
        }
    }
}

이렇게 ScoreItem과 EffectItem의 부모 클래스인 Item 클래스에서 아이템 획득 시 해당 아이템 Prefab에 부여된 AudioSource를 재생할 수 있게 구현했다.
그런데 해당 방식으로 효과음을 관리하게 되면 아이템 Destroy 기능과 중첩돼 효과음 조절이 어렵고, 아이템 Prefab마다 AudioSource를 적용시켜줘야 해서 BGM과 함께 AudioManager에서 관리하면 좋다는 피드백을 받음.
그래서 BGM과 SFX를 관리하는 AudioManager 스크립트를 다시 구현.

// SFX(게임 효과음) 열거형
public enum SFXType
{
    Jump,           // Element 0
    Slide,          // Element 1
    Hit,            // Element 2
    Die,            // Element 3
    ScoreItem,      // Element 4
    ItemChicken,    // Element 5
    ItemPoison,     // Element 6
    ItemFireball    // Element 7
}

public class AudioManager : MonoBehaviour
{
    public static AudioManager instance;    // 싱글톤을 위한 인스턴스

    public AudioSource BGM, SFX, UIS;               // 각 유형별 오디오 소스
    public AudioClip[] BGMArr, SFXArr, UISArr;      // 각 오디오 클립 배열

    private void Awake()
    {
        // 싱글톤 패턴 적용
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);  // 씬이 변경되어도 파괴 X
        }
        else
        {
            Destroy(gameObject);    // 기존 AudioManager가 있다면 현재 오브젝트를 삭제
        }
    }

    // BGM 재생
    public void BGMPlay(int numb)
    {
        // 이미 BGM이 재생 중이라면 정지
        if (BGM.isPlaying)
        {
            BGM.Stop();
        }
        
        // 배열 범위 내에서만 실행되도록 검사
        if (numb >= 0 && numb < BGMArr.Length)
        {
            BGM.clip = BGMArr[numb];    // 선택한 BGM 클립 설정
            BGM.Play();                 // BGM 재생
        }
    }

    // SFX 재생
    public void SFXPlay(SFXType type)
    {
        int index = (int)type;      // SFXType 열거형을 정수로 변환
        
        // 배열 범위 내에서만 실행되도록 검사
        if (index >= 0 && index < SFXArr.Length)
        {
            SFX.PlayOneShot(SFXArr[index]); // 효과음 한 번 재생
        }
    }
    
    // UI 사운드 재생
    public void UISPlay(UISType type)
    {
        int index = (int)type;      // UISType 열거형을 정수로 변환
        
        // 배열 범위 내에서만 실행되도록 검사
        if (index >= 0 && index < UISArr.Length)
        {
            UIS.PlayOneShot(UISArr[index]); // 효과음 한 번 재생
        }
    }
}

이렇게 AudioManager 스크립트를 만들어 주면 하나의 인스펙터 창에서 BGM과 SFX를 관리해 줄 수 있어서 편리하다.

// EffectItem 스크립트

	// 아이템 효과 적용
    private void ApplyEffect(Player player)
    {
        switch (itemType)
        {
            case ItemType.Chicken:
                player.Heal(10);    // 체력 10 회복
                AudioManager.instance.SFXPlay(SFXType.ItemChicken);
                break;
            case ItemType.Fireball:
                player.SpeedUp(5f, 5f); // 속도 2 증가, 5초 후 원래 속도로 복귀
                AudioManager.instance.SFXPlay(SFXType.ItemFireball);
                break;
            case ItemType.Poison:
                player.StartCoroutine(player.TakePoisonDamage(3, 5, 0.5f)); // 3 데미지, 5번 반복, 0.5초 간격
                AudioManager.instance.SFXPlay(SFXType.ItemPoison); 
                break;
            case ItemType.HpPotion:
                player.Heal(15);    // 체력 15 회복
                AudioManager.instance.SFXPlay(SFXType.ItemChicken);
                break;
        }
    }

이런 식으로 효과음이 들어갈 구간에 AudioManager.instance.SFXPlay(SFXType.Item~) 코드를 작성해 주면 반영됨!
아이템이 사라지는 것과는 관계없이 효과음이 실행되기 때문에 보다 편하고 안전하다.

profile
...

0개의 댓글