MP3 Player -> AudioSource
MP3 음원 -> AudioClip
관객(귀) -> AudioListener
한씬에 하나씩만 있으면 되는데 대부분 default로 Main Camera에 달려있다
AudioClip : 들을 소리
Play On Awake : 실행 후 바로 들리게
Volume : 소리크기
Pitch : 재생속도
Loop : 반복
public AudioClip audioClip;
private void OnTriggerEnter(Collider other)
{
AudioSource audio = GetComponent<AudioSource>();
audio.PlayOneShot(audioClip);
}
AudioClip으로 등록한 소리가 난다
public AudioClip audioClip;
public AudioClip audioClip2;
private void OnTriggerEnter(Collider other)
{
AudioSource audio = GetComponent<AudioSource>();
audio.PlayOneShot(audioClip);
audio.PlayOneShot(audioClip2);
}
소리가 겹쳐서 두가지 나게된다
public AudioClip audioClip;
private void OnTriggerEnter(Collider other)
{
AudioSource audio = GetComponent<AudioSource>();
audio.PlayOneShot(audioClip);
Destroy(gameObject, 0.2f);
}
게임오브젝트가 파괴될 시 소리가 바로 끊기게 된다
public AudioClip audioClip;
public AudioClip audioClip2;
private void OnTriggerEnter(Collider other)
{
AudioSource audio = GetComponent<AudioSource>();
audio.PlayOneShot(audioClip);
audio.PlayOneShot(audioClip2);
float lifeCycle = Mathf.Max(audioClip.length, audioClip2.length);
Destroy(gameObject, lifeCycle);
}
audioClip 둘중 더 긴 시간이 지난뒤에 물체를 파괴하면 정상적으로 소리가 들린뒤에 파괴된다
Animation 이런것도 있는데 사운드만 가지고 생명주기를 만드는건 올바르지 않다
AudioSource를 물쳬(여기서는 큐브)가 아니라 사운드 매니저에 넣어두면 더 괜찮지 않을까?
public enum Sound
{
Bgm,
Effect,
MaxCount,
}
enum으로 Bgm/Effect를 구분한다
AudioSource는 new로 만들지 못하기 때문에 아래와 같이 Init으로 만들어줘야한다
AudioSource[] _audioSources = new AudioSource[((int)Define.Sound.MaxCount)];
public void Init()
{
//Sound Manager를 담아둘 게임오브젝트만들기
GameObject root = GameObject.Find("@Sound");
if(root == null)
{
root = new GameObject { name = "@Sound" };
Object.DontDestroyOnLoad(root);
//Define.Sound 목록의 이름가진 게임오브젝트만듬
string[] soundNames = System.Enum.GetNames(typeof(Define.Sound));
for(int i = 0; i < soundNames.Length - 1; i++)
{
GameObject go = new GameObject { name = soundNames[i] };
_audioSources[i] = go.AddComponent<AudioSource>();
go.transform.parent = root.transform;
}
_audioSources[(int)Define.Sound.Bgm].loop = true;
}
}
//음반의 경로, 속도조절
public void Play(string path, Define.Sound type = Define.Sound.Effect, float pitch = 1.0f)
{
//Sounds라는 경로가 없다면 Sounds경로를 넣어줌
if(path.Contains("Sounds/") == false)
path = $"Sounds/{path}";
//bgm같은 경우는 루프 돌려야 하기 때문에
if(type == Define.Sound.Bgm)
{
AudioClip audioClip = Managers.Resource.Load<AudioClip>(path);
//혹시 audioClip이 null이라면
if(audioClip == null)
{
Debug.Log($"AudioClip Massing ! {path}");
return;
}
//이미 실행된 BGM이 있다면 멈추기
AudioSource audioSource = _audioSources[(int)Define.Sound.Bgm];
if (audioSource.isPlaying)
audioSource.Stop();
audioSource.pitch = pitch;
audioSource.clip = audioClip;
audioSource.Play();
}
//단발성 사운드
else
{
AudioClip audioClip = Managers.Resource.Load<AudioClip>(path);
//혹시 audioClip이 null이라면
if (audioClip == null)
{
Debug.Log($"AudioClip Massing ! {path}");
return;
}
AudioSource audioSource = _audioSources[(int)Define.Sound.Effect];
audioSource.pitch = pitch;
audioSource.PlayOneShot(audioClip);
}
}
매번 OnTriggerEnter가 작동하면 BGM이 바뀌게 된다
int i = 0;
private void OnTriggerEnter(Collider other)
{
i++;
if(i % 2 == 0)
Managers.Sound.Play("Unitychan/univ0001", Define.Sound.Bgm);
else
Managers.Sound.Play("Unitychan/univ0002", Define.Sound.Bgm);
}
그냥 Effect는 아래와 같이 사용하면 된다
Managers.Sound.Play("Unitychan/univ0003");
단발성 사운드는 여러번 실행되기에 매번 Load해오기에는 메모리에 부담가서 캐싱이 필요하다
AudioClip audioClip = Managers.Resource.Load<AudioClip>(path);
저장하기 위해서 Dictionary를 추가해준다
Dictionary<string, AudioClip> _audioClips = new Dictionary<string, AudioClip>();
Dictionary에 저장된 오디오클립이 없다면 추가될 것이며
있다면 기록에 남아있는것을 반환한다
AudioClip GetOrAddAudioClip(string path)
{
AudioClip audioClip = null;
//이전에 저장된 오디오 클립이 없다면 추가해줌
if(_audioClips.TryGetValue(path, out audioClip) == false)
{
audioClip = Managers.Resource.Load<AudioClip>(path);
_audioClips.Add(path, audioClip);
}
return audioClip;
}
그리고 단발성 사운드는
//단발성 사운드
else
{
//단발성 사운드는 여러번 실행되기에 매번 Load해오기에는 메모리에 부담간다 캐싱이 필요하다
AudioClip audioClip = GetOrAddAudioClip(path);
//혹시 audioClip이 null이라면
if (audioClip == null)
{
Debug.Log($"AudioClip Massing ! {path}");
return;
}
AudioSource audioSource = _audioSources[(int)Define.Sound.Effect];
audioSource.pitch = pitch;
audioSource.PlayOneShot(audioClip);
}
이렇게 구현하면 조금더 메모리의 이점을 가져올 수 있다
DontDestroyOnLoad에 캐싱역할을 하는 딕셔너리가 저장되어 있는데
새로운 사운드를 계속해서 누적이 될 것이다 그러다보면 메모리에 영향을 끼친다 그래서 Clear하는 부분도 추가해준다
public void Clear()
{
foreach(AudioSource audioSource in _audioSources)
{
audioSource.clip = null;
audioSource.Stop();
}
_audioClips.Clear();
}
씬이 바뀔때 Clear해야 하지만 Sound 뿐만 아니라 다른것도 Clear를 만들 수 가 있어서 Manager에 Clear부분을 만들어둔다
public static void Clear()
{
Sound.Clear();
Input.Clear();
Scene.Clear();
UI.Clear();
}
Manager를 사용해서 지금현재 처리 안되는 부분2가지
1.3D사운드(물체가 멀어지면 멀어질수록 소리 작아지게)
2.유저가 스킬 시전하는도중에 채널링 사운드가 날 때 죽거나 움직여서 그 사운드를 실시간으로 끊기
Spatial Blend를 Right로 놔두면 3D사운드 구현이 가능하고
아래 그래프로 거리에 따라서 어떻게 들릴지 표현하는 그래프