BGM・SEを管理する専用のクラス、SoundManagerを作成します。どこのクラスから使用されてもいいようにシングルトンにします。
public class SoundManager
{
private readonly AudioSource bgmAudioSource;
private readonly AudioSource seAudioSource;
private readonly AudioClip[] allAudioPool;
private readonly Dictionary<string, AudioClip> bgmPool =
new Dictionary<string, AudioClip>();
private readonly Dictionary<string, AudioClip> sePool =
new Dictionary<string, AudioClip>();
public static SoundManager Instance { get; } = new SoundManager();
public void LoadBGM(string key, string name)
{
if (bgmPool.ContainsKey(key)) return;
var audio = GetAudioClip(name);
bgmPool.Add(key, audio);
}
public void LoadSE(string key, string name)
{
if (sePool.ContainsKey(key)) return;
var audio = GetAudioClip(name);
sePool.Add(key, audio);
}
public void PlayBGM(string name, float volume = 1)
{
if (bgmPool[name] == null) throw new Exception("not found");
bgmAudioSource.clip = bgmPool[name];
bgmAudioSource.loop = true;
bgmAudioSource.volume = Mathf.Clamp01(volume);
bgmAudioSource.Play();
}
public void PlaySE(string name, float volume = 1)
{
if (sePool[name] == null) throw new Exception("not found");
volume = Mathf.Clamp01(volume);
seAudioSource.PlayOneShot(sePool[name], volume);
}
public void StopBGM()
{
bgmAudioSource.Stop();
}
public void PauseBGM()
{
if (bgmAudioSource.isPlaying) bgmAudioSource.Pause();
else bgmAudioSource.UnPause();
}
public void StopSE()
{
seAudioSource.Stop();
}
private SoundManager()
{
allAudioPool = Resources.LoadAll<AudioClip>("Audio");
var obj = new GameObject("SoundManager");
bgmAudioSource = obj.AddComponent<AudioSource>();
seAudioSource = obj.AddComponent<AudioSource>();
UnityEngine.Object.DontDestroyOnLoad(obj);
}
private AudioClip GetAudioClip(string name)
{
var audio = allAudioPool.FirstOrDefault(a => a.name == name);
if (audio == null) throw new Exception("not found");
return audio;
}
}
GameManagerの起動時にAudioClipを読み込みます。
public class GameManager : MonoBehaviour
{
private SoundManager soundManager;
private void Awake()
{
SetAudio();
}
private void SetAudio()
{
soundManager = SoundManager.Instance;
soundManager.LoadSE("EatDot", "Byu");
soundManager.LoadSE("EatPowerCokie", "ByChance");
soundManager.LoadSE("EatGhost", "Byuu");
soundManager.LoadSE("Dead", "Qyurururu");
soundManager.LoadBGM("GhostNormal", "Panic");
soundManager.LoadBGM("GhostScare", "LFO");
soundManager.LoadSE("GhostDead", "Obake");
}
}
再生したい部分でPlayBGM、PlaySEを実行します。
[SerializeField] private Text readyText = default;
private List<AGhost> ghosts;
private Pacman pacman;
private SoundManager soundManager;
private bool isScare;
private float scareEndTime;
private int eatenGhost;
private void FixedUpdate()
{
if (isScare && scareEndTime < Time.fixedTime )
{
isScare = false;
eatenGhost = 0;
ghosts.ForEach(g => g.Calm());
soundManager.StopBGM();
soundManager.PlayBGM("GhostNormal", 0.6f);
}
}
private IEnumerator CoroutineStart(Action callback)
{
readyText.gameObject.SetActive(true);
callback();
yield return new WaitForSeconds(readySpan);
readyText.gameObject.SetActive(false);
pacman.Run();
ghosts.ForEach(g => g.Run());
soundManager.PlayBGM("GhostNormal", 0.6f);
}
public class Dead : IState
{
private readonly Mover mover;
private readonly Animator animator;
private readonly SoundManager soundManager;
public void SetState()
{
mover.SetWaypoints(nestWaypoints);
mover.Speed = defaultSpeed * 2f;
animator.SetBool("IsScare", false);
animator.SetBool("IsCalmSoon", false);
animator.SetBool("IsDead", true);
soundManager.PlaySE("GhostDead", 0.2f);
}
}