유니티에서 오디오는 오브젝에 첨부된 Audio Source Component로 부터의 사운드가 필요하고, 이를 들을 Audio Listener Component가 필요하다.
Audio Listener Component는 주로 카메라에 부착시키며 AudioListener는 오직 씬에 하나만 존재할 수 있다.
Unity는 AIFF, WAV, MP3, Ogg 포멧의 오디오 파일을 Poject 패널에 드래그하는 것만으로 임포트가 가능하다. 이렇게 임포트 된 오디오 파일을 Audio Clip이라고 부른다.
오디오는 파일을 참조만 할 뿐 런타임 시점에서 로드되는 방식이다. 따라서 옵션을 줘가지고 발자국 같은 소리는 오디오 에셋을 메모리에 유지시켜야 한다.
Audio Source는 오디오 클립을 재생한다. 설정을 통해 Audio Listenr와의 거리에 따라서 들리는 최소 거리와, 최대 거리 그리고 최소와 최대를 이을 때 Linear하게 할건지 등을 할 수 있다.
Audio Source의 몇가지 프로퍼티를 보겟다.
Loop : 옵션을 활성화하면 재생이 끝날 때 Audio Clip 루프가 생성된다.
Priority : 우선순위 0은 최우선 순위고, 우선순위 256은 최하위 순위로 디폴드 값은 128이다. 순위가 잘못 바뀌는 경우를 막기위해 음악 트랙은 0으로 설정해야 한다.
Volume : AudioListener로부터 1월드 유닛 거리에서 소리가 얼마나 크게 들릴지를 정의한다.
3D Sound Setting : 공간 블렌드 파라미터에 비례해 적용된다.
Play On Awake : 옵션 활성화 시 씬이 실행되는 시점에 사운드 재생이 시작됩니다. 이 옵션을 비활성화 하면 스크립팅에서 Play() 명령을 사용하여 사운드 재생을 해야 한다.
추가로 AudioReverbZone이라는 것을 통해 거리에 따른 여러 효과를 쉽게 줄 수도 있다.
참고로 Audio Source에서 소리가 중첩되어도 소리가 중첩되서 들리며, Audio Clip을 잃어버리지 않는한 재생된다.
이제 AudioManager를 만들어보자. 설계는 다음과 같다.
1. 브금용 Audio Source / 효과음용 Audio Source를 만들 것이다.
2. 브금용은 Loop로 재생되며 효과음은 한번 재생하고 종료된다.
// Define.cs
public enum AudioSource
{
BGM,
EFFECT,
MAT_COUNT
}
먼저 다음과 같이 AudioSource 용도를 미리 정해놓겠다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioManager
{
AudioSource[] audioSource = new AudioSource[(int)Define.AudioSource.MAT_COUNT];
Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();
public void Init()
{
GameObject root = GameObject.Find("@Audio");
if (root != null)
return;
root = new GameObject("@Audio");
Object.DontDestroyOnLoad(root);
string[] names = typeof(Define.AudioSource).GetEnumNames();
for(int i=0; i < (int)Define.AudioSource.MAT_COUNT; i++)
{
GameObject audioObjcet = new GameObject(names[i]);
audioSource[i] = audioObjcet.AddComponent<AudioSource>();
audioObjcet.transform.parent = root.transform;
}
audioSource[(int)Define.AudioSource.BGM].loop = true;
audioSource[(int)Define.AudioSource.EFFECT].loop = false;
}
public void Play(string path, Define.AudioSource audioType = Define.AudioSource.EFFECT)
{
Play(GetAudioClip(path, audioType), audioType);
}
public void Play(AudioClip audioClip, Define.AudioSource audioType = Define.AudioSource.EFFECT)
{
if (audioClip == null)
return;
if(audioType == Define.AudioSource.BGM) {
if(audioSource[(int)Define.AudioSource.BGM].isPlaying)
audioSource[(int)Define.AudioSource.BGM].Stop();
audioSource[(int)Define.AudioSource.BGM].clip = audioClip;
audioSource[(int)Define.AudioSource.BGM].Play();
}
else if(audioType == Define.AudioSource.EFFECT){
audioSource[(int)Define.AudioSource.EFFECT].PlayOneShot(audioClip);
}
}
public AudioClip GetAudioClip(string path, Define.AudioSource audioType = Define.AudioSource.EFFECT)
{
AudioClip clip = null;
// 브금은 용량이 크므로 저장해놓지 않음.
if (audioType == Define.AudioSource.BGM)
{
UnityEngine.Object obj = Resources.Load(path);
if (obj == null)
return clip;
clip = Object.Instantiate(obj) as AudioClip;
}
else if(audioType == Define.AudioSource.EFFECT)
{
if(audioClips.TryGetValue(path,out clip) == false)
{
UnityEngine.Object obj = Resources.Load(path);
if (obj == null)
return clip;
clip = Object.Instantiate(obj) as AudioClip;
if(clip != null)
audioClips.Add(path, clip);
}
}
return clip;
}
}