효과음이 재생안되던 문제
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Player")) // 플레이어와 충돌했을 때
{
HealthSystem healthSystem = collision.GetComponent<HealthSystem>();
if (healthSystem.CurrentHealth < healthSystem.MaxHealth)
{
healthSystem.ChangeHealth(healAamount);
SoundManager.Sound.Play("DrinkPotion.mp3", SoundType.Effect);
gameObject.SetActive(false);
}
}
}
위의 코드는 회복 아이템이 캐릭터랑 충돌이나면 캐릭터의 체력이 1 증가하고, 회복 아이템이 사라지는 코드이다.
SoundManager.Sound.Play("DrinkPotion.mp3", SoundType.Effect);
원래 이 자리에 해당 오브젝트에 부착되어 있던 오디오 클립으로 효과음을 재생시키는 코드가 있었다.
gameObject.SetActive(false);
그런데 위의 코드가 너무 빨리 실행되니까 포션이 없어지면서 효과음도 같이 없어졌다. 왜냐하면 포션에 AudioSource가 부착되어 있었기 때문이다.
해결 방법 - SoundManger.cs
그래서 `SoundManager.cs`를 만들어서 배경음과 효과음을 관리하기로 했다.
public class SoundManager : MonoBehaviour
{
private static SoundManager _instance;
public static SoundManager Sound
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<SoundManager>();
if (_instance == null)
{
GameObject soundManager = new GameObject("SoundManager");
_instance = soundManager.AddComponent<SoundManager>();
DontDestroyOnLoad(soundManager);
}
}
return _instance;
}
}
private void Awake()
{
if (_instance == null)
{
_instance = this;
DontDestroyOnLoad(gameObject);
Init();
}
else if (_instance != this)
{
Destroy(gameObject);
}
}
}
우선 사운드매니저는 싱글톤으로 만들었다. 그래야 어느 스크립트에서든 사운드매니저를 통해 음악을 재생할 수 있기 때문이다.
public enum SoundType
{
Bgm,
Effect,
MaxCount, // 아무것도 아님, 끝을 알기 위함
}
// 배경음, 효과음 중첩이 가능하기 위함
private AudioSource[] _audioSources = new AudioSource[(int)SoundType.MaxCount];
private Dictionary<string, AudioClip> _audioClips = new Dictionary<string, AudioClip>();
그리고 AudioSource는 배경음, 효과음 각각 따로 생성했다.
왜냐하면 배경음이 실행되는 도중 끊기지 않고 효과음도 중첩으로 실행될 수 있게 하기 위함이다.
public void Init()
{
GameObject root = GameObject.Find("@Sound");
if (root == null)
{
root = new GameObject { name = "@Sound" };
Object.DontDestroyOnLoad(root);
string[] soundNames = System.Enum.GetNames(typeof(SoundType));
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)SoundType.Bgm].loop = true; // 배경음은 무한 반복 재생
}
}
Init()이 실행되면 위의 그림처럼 배경음, 효과음 따로 오브젝트가 생성되고, 각각 AudioSource 컴포넌트가 부착된다.
// 배경음, 효과음 재생
public void Play(AudioClip clip, SoundType type = SoundType.Effect, float volume = 1.0f) // = 디폴트값
{
if (clip == null)
return;
if (type == SoundType.Effect)
{
AudioSource audioSource = _audioSources[(int)SoundType.Effect];
if (audioSource.isPlaying)
{
audioSource.Stop();
}
audioSource.volume = volume;
audioSource.PlayOneShot(clip); // 한 번만 재생
}
else // Sound.Bgm
{
AudioSource audioSource = _audioSources[(int)SoundType.Bgm];
audioSource.volume = volume;
audioSource.clip = clip;
audioSource.Play();
}
}
효과음, 배경음에 따라 `PlayOneShot`방식과 `Play`방식으로 나뉜다.
효과음은 한 번만 실행하고, 배경음은 계속 실행되기 때문이다.
if (audioSource.isPlaying)
{
audioSource.Stop();
}
효과음에 위의 코드를 넣은 이유는 효과음이 2개가 한 번에 연속으로 재생될 때 A효과음에서 B효과음으로 넘어가면서 A효과음의 볼륨설정값이 B효과음 재생시에 잠깐 반영된 후 원하던 볼륨으로 돌아오기 때문이다.
public void Play(string path, SoundType type = SoundType.Effect, float volume = 1.0f)
{
AudioClip audioClip = GetOrAddAudioClip(path, type);
Play(audioClip, type, volume);
}
AudioClip GetOrAddAudioClip(string path, SoundType type = SoundType.Effect)
{
if (path.Contains("Assets/Sounds") == false)
path = $"Assets/Sounds/{path}"; // Sound 폴더 안에 저장될 수 있도록
AudioClip audioClip = null;
if (type == SoundType.Bgm) // BGM 배경음악 클립 붙이기
{
audioClip = AssetDatabase.LoadAssetAtPath<AudioClip>(path);
}
else // Effect 효과음 클립 붙이기
{
if (_audioClips.TryGetValue(path, out audioClip) == false)
{
audioClip = AssetDatabase.LoadAssetAtPath<AudioClip>(path);
_audioClips.Add(path, audioClip);
}
}
if (audioClip == null)
Debug.Log($"AudioClip Missing ! {path}");
return audioClip;
}
이 코드는 음악 파일이 있는 경로안의 오디오 클립을 가져와 실행시키기 위해 작성됐다.
SoundManager.Sound.Play("Explode.mp3", SoundType.Effect, 0.2f);
사용방법은 위와 같다.
"Assets/Sounds" 경로까지는 같기 때문에 뒤에 "Explode.mp3"만 적어주면 해당 음악 클립이 재생된다.
타입은 효과음이고, 볼륨이 0.2f이다.
해결 후 성과
- 효과음이 실행될 오브젝트마다 AudioSource 컴포넌트를 부착해주고, 클립을 달아주고, 소스코드에서는 해당 컴포넌트 불러와서 재생시켜주는 이 과정들이 점점 늘어날수록 너무 귀찮았다.
- 더욱 문제인점은 이 오브젝트가 삭제되면 AudioSource 컴포넌트도 같이 삭제되는 것이기 때문에 효과음도 같이 사라진다는 것이다.
그래서 SoundManager.cs를 만들어 배경음과 효과음을 관리하는 로직을 작성해보는 경험을 해봐서 실력이 향상된 것 같다.
댓글