Unityで汎用性の高いSoundManagerの作成

SoundManager.csのクラス名は何でもよいが、AudioPlayer.csがしっくりくるかもしれない。


参考文献
こちらを自分なりに拡張しました。
https://qiita.com/simanezumi1989/items/681328f30e88737f57b0

# C# 

↓サウンドマネージャー
GameObjectにつける
```SoundManager.cs
using System.Collections.Generic;
using UnityEngine;

public class SoundManager : MonoBehaviour
{
    [SerializeField] AudioSource bgmAudioSource;
    [SerializeField] AudioSource seAudioSource;

    [SerializeField] List<BGMSoundData> bgmSoundDatas;
    [SerializeField] List<SESoundData> seSoundDatas;

    public float masterVolume = 1;
    public float bgmMasterVolume = 1;
    public float seMasterVolume = 1;

    public static SoundManager Instance { get; private set; }

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }

    public void PlayBGM(BGMSoundData.BGM bgm)
    {
        BGMSoundData data = bgmSoundDatas.Find(data => data.bgm == bgm);
        bgmAudioSource.clip = data.audioClip;
        bgmAudioSource.volume = data.volume * bgmMasterVolume * masterVolume;
        bgmAudioSource.Play();
    }

    public void StopBGM(BGMSoundData.BGM bgm)
    {
        BGMSoundData data = bgmSoundDatas.Find(data => data.bgm == bgm);
        bgmAudioSource.clip = data.audioClip;
        bgmAudioSource.volume = 0;
        bgmAudioSource.Stop();
    }


    public void PlaySE(SESoundData.SE se, Vector3 position)
    {
        SESoundData data = seSoundDatas.Find(data => data.se == se);
        seAudioSource.volume = data.volume * seMasterVolume * masterVolume;
        AudioSource.PlayClipAtPoint(data.audioClip, position);
    }
}

[System.Serializable]
public class BGMSoundData
{
    public enum BGM
    {
        Title,
        Dungeon,
        WARNING,// これがラベルになる
    }

    public BGM bgm;
    public AudioClip audioClip;
    [Range(0, 1)]
    public float volume = 1;
}

[System.Serializable]
public class SESoundData
{
    public enum SE
    {
        Dead,
        ItemGet,
        Goal,
        CAVEAT,// これがラベルになる
    }

    public SE se;
    public AudioClip audioClip;
    [Range(0, 1)]
    public float volume = 1;
}
```

↓スタート時にBGMを流す
GameObjectにつける
```MusicPlayer.cs
using UnityEngine;

public class MusicPlayer : MonoBehaviour
{
    [SerializeField] BGMSoundData.BGM bgm;

    void Start()
    {
        SoundManager.Instance.PlayBGM(bgm);
    }
}
```

↓私がよく使うゲームオーバー時のBGMの切り替え実装方法
プレイヤーのtagのついたオブジェクトにつける
```PlayerLife.cs
using UnityEngine;
using UnityEngine.Events;

public class PlayerLife : MonoBehaviour
{
    public int playerLife = 100;
    public bool isGameOver;
    public BGMSoundData.BGM warning;

    public static UnityEvent OnGameOver = new UnityEvent();

    private void Awake()
    {
        OnGameOver.RemoveAllListeners();
        OnGameOver.AddListener(() =>
        {
            isGameOver = true;
            Debug.Log($"isGameOver: {isGameOver}");
            SoundManager.Instance.PlayBGM(warning);
        });
    }

    public void Damage(int damage)
    {
        if (playerLife <= 0) return;

        playerLife -= damage;

        if (playerLife <= 0)
        {
            OnDie();
        }
    }

    void OnDie()
    {
        OnGameOver.Invoke();
    }
}

```

### 敵キャラクターコライダーにPlayerのTagがついたオブジェクトが当たりプレイヤーのライフが0になるとBGMが変わる
敵のオブジェクトにつける
```Enemy.cs
using UnityEngine;

public class Enemy : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        GameObject gameObj = collision.gameObject;

        if(collision.gameObject.tag == "Player")
        {
            PlayerLife playerLife = gameObj.GetComponent<PlayerLife>();
            playerLife.Damage(10);
            Debug.Log($"playerのライフ: {playerLife.playerLife}");
        }
    }
}
```

##### おまけ
↓こうするとゲームオーバーになったときプレイヤーの操作入力を受け付けなくすることができる
```PlayerMove.cs

void Update(){
    PlayerLife.OnGameOver.AddListener(() =>
    {
        return;
    });

    // プレイヤーの移動処理
    /*
    省略
    */
}
```