[unity] 모듈 제작 : 사운드 플레이어 만들기(1)
앱 및 게임 제작 시 공통으로 사용하는 모듈을 제작해보자. 첫번째 제작 모듈은 사운드 플레이어 모듈이다. 사운드 플레이 기능은 각 씬이나 화면에서 공통으로 사용할 수 있게 모듈화 해 놓으면 상당히 유용하다.
1. 사운드 플레이어 모듈 제작 준비
- 유니티 버전은 2019 LTS 버전을 사용한다. (상위 버전에서도 큰 문제는 없다.)
- Assets/Moduls/Sound 폴더를 생성한다. ( 마우스 우클릭 -> Create -> Folder )
- Sound 폴더 밑에 Prefabs와 Scripts 폴더를 생성한다.
2. 사운드 플레이어 모듈 기능 정의
- 하나의 사운드는 메모리에 올려져 있으며, 2개 이상 사운드가 동시에 출력되야 할 경우(이펙트 사운드) 하나를 추가적으로 동적으로 생성해서 재생한다.
- 사운드는 BGM 과 Effect 로 나눠서 구분 ( BGM은 기본적으로 Loop 재생, Effect 사운드는 짧게 재생 후 소멸의 차이점을 가짐) 한다.
- 사운드의 재생, 일시정지, 멈춤 등의 기능을 제공한다.
- 사운드의 볼륨 제어한다.
- 싱글톤 클래스로 제작하여, 씬 이동 간 영향을 받지 않도록 구성한다.
3. 사운드 플레이어 스크립트 작성
- Scripts 폴더에 C# 스크립트인 SoundPlayer.cs를 생성한다. ( 마우스 우클릭 -> Create -> C# Script )
- SoundPlayer.cs 의 코드를 아래와 같이 작성해 주자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace Container.Sound
{
/// <summary>
/// 사운드 플레이어 클래스
/// 싱글톤으로 관리
/// 기본 1개 SoundObject를 사용하며, 두개 이상 동시 사운드 처리시 SoundObject 동적으로 생성
/// </summary>
public class SoundPlayer : MonoBehaviour
{
public static SoundPlayer Instance { get; private set; }
[SerializeField]
protected AudioSource audio_bgm = null;
[SerializeField]
protected SoundObject audio_basic = null;
[SerializeField]
protected AudioClip[] arr_AudioEffectClip = null;
protected List<SoundObject> list_Sound = new List<SoundObject>();
protected Dictionary<SoundType, AudioClip> dic_EffectSound = new Dictionary<SoundType, AudioClip>();
protected readonly string SOUND_NAME = "_Sound";
protected readonly float BGM_VOLUME = 0.5f;
void Awake()
{
Instance = this;
dic_EffectSound.Clear();
list_Sound.Add(audio_basic);
for (int i = 0; i < arr_AudioEffectClip.Length; i++)
{
dic_EffectSound.Add((SoundType)Enum.Parse(typeof(SoundType), arr_AudioEffectClip[i].name), arr_AudioEffectClip[i]);
}
}
/// <summary>
/// This function is called when the MonoBehaviour will be destroyed.
/// </summary>
void OnDestroy()
{
Instance = null;
}
public bool IsBgmPlaying
{
get{
return audio_bgm.isPlaying;
}
}
/// <summary>
/// 사운드 재생 중인지 여부.
/// </summary>
public bool IsPlaying()
{
foreach (SoundObject snd in list_Sound)
{
if (snd.IsPlaying)
{
return true;
}
}
return false;
}
public bool IsPause()
{
if (Time.timeScale <= 0)
return true;
return false;
}
/// <summary>
/// 사운드 재생 중인지 여부.
/// </summary>
public bool IsPlaying(AudioClip clip)
{
foreach (SoundObject snd in list_Sound)
{
if (snd.Clip == clip)
{
if (snd.IsPlaying)
{
return true;
}
}
}
return false;
}
/// <summary>
/// get Sound Clip
/// </summary>
/// <returns>The sound clip.</returns>
/// <param name="type">Common Sound Type.</param>
public AudioClip GetSoundClip(SoundType type)
{
if (dic_EffectSound.ContainsKey(type))
{
return dic_EffectSound[type];
}
else
return null;
}
#region BGM
public void PlayBGM(AudioClip clip)
{
PlayBGM(clip, BGM_VOLUME);
}
public void PlayBGM(AudioClip clip, float volume)
{
PlayBGM(clip, volume, true);
}
public void PlayBGM(AudioClip clip, float volume, bool isloop)
{
if (clip == null)
{
Debug.Log("BGM clip is null");
return;
}
if(IsBgmPlaying)
{
audio_bgm.Stop();
}
audio_bgm.clip = clip;
audio_bgm.volume = volume;
audio_bgm.loop = isloop;
audio_bgm.Play();
}
public void StopBGM()
{
audio_bgm.Stop();
}
public void PauseBGM()
{
if (audio_bgm.isPlaying)
audio_bgm.Pause();
}
public void UnpausBGM()
{
audio_bgm.UnPause();
}
#endregion
#region PlaySound
/// <summary>
/// 사운드 플레이
/// </summary>
/// <param name="soundType">Sound type.</param>
public void PlaySound(SoundType soundType)
{
PlaySound(soundType, true);
}
/// <summary>
/// 사운드 플레이
/// </summary>
/// <param name="soundType">Sound type.</param>
/// <param name="isStopEnable">If set to <c>true</c> is stop enable.</param>
public void PlaySound(SoundType soundType , bool isStopEnable)
{
if (soundType == SoundType.None) return;
PlaySound(GetSoundClip(soundType), 1f, 0, false, isStopEnable, null);
}
public void PlaySound(SoundType soundType, float volume){
if (soundType == SoundType.None) return;
PlaySound(GetSoundClip(soundType), volume, null);
}
public void PlaySound(AudioClip clip)
{
PlaySound(clip, null);
}
public IEnumerator CoPlaySound(AudioClip clip, float minWaitSec = 0.5f){
float waitSec = (clip != null && clip.length > minWaitSec) ? clip.length : minWaitSec;
PlaySound(clip, null);
yield return new WaitForSeconds(waitSec);
}
/// <summary>
/// 사운드 재생
/// </summary>
/// <param name="clip">Clip.</param>
/// <param name="finishListener">Finish listener.</param>
public void PlaySound(AudioClip clip, System.Action finishListener)
{
PlaySound(clip, 1f, finishListener);
}
/// <summary>
/// 사운드 재생
/// </summary>
/// <param name="clip">Audio Clip.</param>
/// <param name="volume">Audio Volume. 0 ~ 1</param>
/// <param name="finishListener">Finish listener.</param>
public void PlaySound(AudioClip clip, float volume, System.Action finishListener)
{
PlaySound(clip, volume, 0, false, finishListener);
}
/// <summary>
/// 사운드 재생
/// </summary>
/// <param name="clip">Audio Clip.</param>
/// <param name="volume">Audio Volume. 0 ~ 1</param>
/// <param name="delaySeonds">사운드 플레이 전 delay 초</param>
/// <param name="finishListener">Finish listener.</param>
public void PlaySound(AudioClip clip, float volume, float delaySeonds, System.Action finishListener)
{
PlaySound(clip, volume, delaySeonds, false, finishListener);
}
/// <summary>
/// 사운드 재생
/// </summary>
/// <param name="clip">Audio Clip.</param>
/// <param name="volume">Audio Volume. 0 ~ 1</param>
/// <param name="delaySeonds">사운드 플레이 전 delay 초</param>
/// <param name="isLoop">If set to <c>true</c> is loop.</param>
/// <param name="finishListener">Finish listener.</param>
public void PlaySound(AudioClip clip, float volume,float delaySeonds, bool isLoop, System.Action finishListener)
{
PlaySound(clip, volume, delaySeonds, isLoop, true, finishListener);
}
/// <summary>
/// 사운드 재생
/// </summary>
/// <param name="clip">Audio Clip.</param>
/// <param name="volume">Audio Volume. 0 ~ 1</param>
/// <param name="delaySeconds">사운드 플레이 전 delay 초</param>
/// <param name="isLoop">If set to <c>true</c> is loop.</param>
/// <param name="isStopEnable">If set to <c>true</c> is stop enable.</param>
/// <param name="finishListener">Finish listener.</param>
public void PlaySound(AudioClip clip, float volume, float delaySeconds, bool isLoop, bool isStopEnable, System.Action finishListener)
{
if (clip == null)
{
Debug.Log("Sound Clip is Null");
return;
}
if (IsPlaying() || IsPause())
{
SoundObject obj_Sound = CreateSoundObject(clip);
list_Sound.Add(obj_Sound);
obj_Sound.Play(volume, delaySeconds, isLoop, isStopEnable, () =>
{
list_Sound.Remove(obj_Sound);
if (finishListener != null)
finishListener();
});
}
else
{
audio_basic.Clip = clip;
audio_basic.Play(volume, delaySeconds, isLoop, isStopEnable, () =>
{
if (finishListener != null)
finishListener();
});
}
}
#endregion
/// <summary>
/// Unpauses all sound.
/// </summary>
public void UnpauseAllSound(bool includeBGM = true)
{
foreach (SoundObject snd in list_Sound)
{
snd.unPause();
}
if (includeBGM)
audio_bgm.UnPause();
}
/// <summary>
/// Pauses all sound.
/// </summary>
public void PauseAllSound(bool includeBGM = true)
{
Debug.Log("Pause All Sound");
foreach (SoundObject snd in list_Sound)
{
snd.Pause();
}
if (includeBGM)
audio_bgm.Pause();
}
/// <summary>
/// Stops the sound.
/// </summary>
/// <returns><c>true</c>, if sound was stoped, <c>false</c> otherwise.</returns>
/// <param name="_clip">Clip.</param>
public bool StopSound(AudioClip _clip)
{
for (int i = 0; i < list_Sound.Count; i++)
{
if(list_Sound[i].Clip == _clip)
{
list_Sound[i].Stop();
if(i != 0)
list_Sound.Remove(list_Sound[i]);
return true;
}
}
return false;
}
/// <summary>
/// Stops all sound.
/// 배경음은 stop 제외
/// </summary>
/// <returns><c>true</c>, if all sound was stoped, <c>false</c> otherwise.</returns>
public bool StopAllSound()
{
return StopAllSound(false);
}
/// <summary>
/// Stops all sound.
/// </summary>
/// <returns><c>true</c>, 배경음 포함 모든 사운드 제거 <c>false</c> 배경음 제외 모든 사운드 제거.</returns>
/// <param name="includeBGM">If set to <c>true</c> include bgm.</param>
public bool StopAllSound(bool includeBGM)
{
foreach (SoundObject snd in list_Sound)
{
snd.Stop();
}
if (includeBGM)
audio_bgm.Stop();
ClearAllSound();
return true;
}
/// <summary>
/// Clears all sound.
/// </summary>
protected void ClearAllSound()
{
list_Sound.Clear();
list_Sound.Add(audio_basic);
}
/// <summary>
/// 사운드 객체를 생성하여 리턴
/// </summary>
/// <param name="clip">Audio Clip</param>
/// <returns></returns>
protected SoundObject CreateSoundObject(AudioClip clip)
{
GameObject _soundOBJ = new GameObject(SOUND_NAME);
_soundOBJ.transform.SetParent(audio_basic.transform);
SoundObject snd = _soundOBJ.AddComponent<SoundObject>();
snd.Clip = clip;
return snd;
}
}
}
- 싱글톤 함수이기 때문에, 씬에 해당 스크립트가 올라가져 있으면, SoundPlayer.Instance 를 통해 Instance에 접근할 수 있다.
- PlayBGM() 함수와 PlaySound() 함수를 호출하여, 사운드를 재생시킬 수 있다.
댓글