見出し画像

【Unity】サウンド管理クラスを見直す

いつも使っているSoundManager、AudioVolumeに色々問題があったので、見直しました。


1.SoundManager

プロジェクトのどこからでもサウンドが鳴らせる汎用SoundManagerです。以下の特徴があります。

(1)特徴

  • SEとボイスの再生を分けている。

  • SEとボイスを配列の中からランダム再生する変数。

  • BGMの一時停止と停止を分けている。

  • 決定音とキャンセル音はSoundManager側に設定できる。

(2)使い方

プロジェクト内のどこからでも、SoundManager.i.をつけることで実行できます。音源は呼び出す側のオブジェクトに付けます。

[Header("SEまたはボイス")] public AudioClip playSe;
SoundManager.i.PlayVoice(playSe);

ただし、決定音とキャンセル音は何回も使用されるため、SoundManager側に付けます。

SoundManager.i.PlayClickSe();//決定音を再生
SoundManager.i.PlayCancelSe();//キャンセル音を再生

BGMの一時停止はポーズ時に、BGMに合わせたステージ構成をしている場合等に使用します。

SoundManager.i.PauseBgm();

SEやボイスのランダム再生はキャラゲー等で使用することが多いと思います。

[Header("ダメージ時ボイス")] public AudioClip [] DamageVoices;
SoundManager.i.RandomVoice(DamageVoices);

「ゆっくりまりちゃのだいっぼうけんっ」で多用しました。初期の作品なので全然機能もなくて遊びづらいんですが、ダウンロード数は多いんですよね…。いつかリメイクはしたいと思ってますが…。

(3)コード

using UnityEngine;
using UnityEngine.Audio;

public class SoundManager : MonoBehaviour {
    [SerializeField] AudioSource bgmAudioSource;
    [SerializeField] AudioSource seAudioSource;
    [SerializeField] AudioSource voiceAudioSource;
    [Header("決定音")] [SerializeField] AudioClip clickSe;
    [Header("キャンセル音")] [SerializeField] AudioClip cancelSe;

    public static SoundManager i;
    void Awake() {
        CheckInstance();
    }
    void CheckInstance() {
        if (i == null) {
            i = this;
            DontDestroyOnLoad(gameObject);//シーン遷移しても破棄されない
        } else {
            Destroy(gameObject);
        }
    }

    /// <summary>
    /// BGMを再生
    /// </summary>
    /// <param name="clip"></param>
    public void PlayBgm(AudioClip clip) {
        if (clip){
            bgmAudioSource.clip = clip;
            bgmAudioSource.Play();
        }
    }

    /// <summary>
    /// BGMを再生(引数がない場合)
    /// </summary>
    public void PlayBgm() {
        bgmAudioSource.Play();
    }
    
    /// <summary>
    /// 引数のAudioClip(BGM)の中からランダムに再生
    /// </summary>
    /// <param name="clips"></param>
    public void RandomBgm(params AudioClip[] clips) {
        var randomIndex = UnityEngine.Random.Range(0, clips.Length);
        bgmAudioSource.clip = (clips[randomIndex]);
        bgmAudioSource.Play();
    }
    
    /// <summary>
    /// BGMを一時停止
    /// </summary>
    public void PauseBgm() {
        bgmAudioSource.Pause();
    }
    
    /// <summary>
    /// BGMを停止
    /// </summary>
    public void StopBgm() {
        bgmAudioSource.Stop();
    }

    /// <summary>
    /// 効果音を再生
    /// </summary>
    /// <param name="clip"></param>
    public void PlaySe(AudioClip clip) {
        seAudioSource.PlayOneShot(clip);
    }

    /// <summary>
    /// 引数のAudioClip(SE)の中からランダムに再生
    /// </summary>
    /// <param name="clips"></param>
    public void RandomSe(params AudioClip[] clips) {
        var randomIndex = UnityEngine.Random.Range(0, clips.Length);
        seAudioSource.PlayOneShot(clips[randomIndex]);
    }

    /// <summary>
    /// SEを停止
    /// </summary>
    public void StopSe() {
        seAudioSource.Stop();
    }

    //決定音を再生
    public void PlayClickSe() {
        seAudioSource.PlayOneShot(clickSe);
    }
    
    //キャンセル音を再生
    public void PlayCancelSe() {
        seAudioSource.PlayOneShot(cancelSe);
    }
    
    /// <summary>
    /// ボイスを再生
    /// </summary>
    /// <param name="clip"></param>
    public void PlayVoice(AudioClip clip) {
        voiceAudioSource.PlayOneShot(clip);
    }

    /// <summary>
    /// 引数のAudioClip(Voice)の中からランダムに再生
    /// </summary>
    /// <param name="clips"></param>
    public void RandomVoice(params AudioClip[] clips) {
        var randomIndex = UnityEngine.Random.Range(0, clips.Length);
        voiceAudioSource.PlayOneShot(clips[randomIndex]);
    }

    /// <summary>
    /// Voiceを停止
    /// </summary>
    public void StopVoice() {
        voiceAudioSource.Stop();
    }
}

2.AudioVolume

オーディオボリュームを記録するクラスです。
以下の記事を参考にAudio MixerとSliderを作成します。

EasySaveを使用しているので、EasySaveがない人はPlayerPrefsに置き換えることで使用可能です。
3のSliderInitializerと組み合わせることで、Sliderがシーン開始時に非アクティブの状態でも問題なく作動します。
Sliderがシーンになくても問題ありません。

using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;

public class AudioVolume : MonoBehaviour {
    public AudioMixer audioMixer;//オーディオミキサーを登録
    public Slider bGMSlider;//BGMのスライダーを登録
    public Slider sESlider;//SEのスライダーを登録
    public Slider voiceSlider;//ボイスのスライダーを登録
    public Slider masterSlider;//マスターのスライダーを登録
    public static AudioVolume i;//AudioVolumeクラスのインスタンスを作成
    
    void Awake() {
        CheckInstance();
    }

    void CheckInstance() {
        if (i == null) {
            i = this;
            DontDestroyOnLoad(gameObject); //シーン遷移しても破棄されない
        }
        else {
            Destroy(gameObject);
        }
    }
    
    private void Start() {
        //BGMとSEのスライダーの位置をロード。データがなければ最大値を入れる。
        float bgmSliderPosition = ES3.Load<float>("BGM_SLIDER", 5.0f);
        float seSliderPosition = ES3.Load<float>("SE_SLIDER", 5.0f);
        float voiceSliderPosition = ES3.Load<float>("VOICE_SLIDER", 5.0f);
        float masterSliderPosition = ES3.Load<float>("MASTER_SLIDER", 5.0f);
        //BGMとSEのセットメソッドを呼び出す
        SetBGM(bgmSliderPosition);
        SetSE(seSliderPosition);
        SetMaster(masterSliderPosition);
        SetVoice(voiceSliderPosition);
        //イベントリスナーを追加
        AddListener();
    }
    
    public void AddListener() {
        // イベントリスナーの追加
        if(bGMSlider != null)
            bGMSlider.onValueChanged.AddListener((value) => {
                SetBGM(value);
                ES3.Save<float>("BGM_SLIDER", value);
            });
        if(sESlider != null)
            sESlider.onValueChanged.AddListener((value) => {
                SetSE(value);
                ES3.Save<float>("SE_SLIDER", value);
            });
        if(voiceSlider != null)
            voiceSlider.onValueChanged.AddListener((value) => {
                SetVoice(value);
                ES3.Save<float>("VOICE_SLIDER", value);
            });
        if(masterSlider != null)
            masterSlider.onValueChanged.AddListener((value) => {
                SetMaster(value);
                ES3.Save<float>("MASTER_SLIDER", value);
            });
    }
    
    //オーディオミキサーの値を取得
    public float GetMixerVolume(string parameterName) {
        float value;
        //オーディオミキサーから値を取得できた場合
        if (audioMixer.GetFloat(parameterName, out value)) {
            return Mathf.Pow(10, value / 20) * 5;  // dBからスライダーの範囲に変換
        }
        return 0f;  // デフォルト値
    }
    
    public void SetBGM(float bgmSliderPosition) {
        //スライダーの位置から相対量をdBに変換してvolumeに入れる
        var volume = Mathf.Clamp(Mathf.Log10(bgmSliderPosition / 5) * 20f, -80f, 0f);
        //スライダーの位置のデータとビジュアルを合わせる
        audioMixer.SetFloat("BGM", volume);
        //bGMSliderがnullでない場合
        if (bGMSlider != null) {
            //オーディオミキサーにvolumeの値をセットする。
            bGMSlider.value = bgmSliderPosition;
            //スライダーの位置をセーブする。
            ES3.Save<float>("BGM_SLIDER", bGMSlider.value);
        }
    }

    public void SetSE(float seSliderPosition) {
        var volume = Mathf.Clamp(Mathf.Log10(seSliderPosition/ 5) * 20f, -80f, 0f);
        audioMixer.SetFloat("SE", volume);
        if (sESlider != null) {
            sESlider.value = seSliderPosition;
            ES3.Save<float>("SE_SLIDER", sESlider.value);
        }
    }

    public void SetVoice(float voiceSliderPosition) {
        var volume = Mathf.Clamp(Mathf.Log10(voiceSliderPosition / 5) * 20f, -80f, 0f);
        audioMixer.SetFloat("Voice", volume);
        if(voiceSlider != null) {
            voiceSlider.value = voiceSliderPosition;
            ES3.Save<float>("VOICE_SLIDER", voiceSlider.value);
        }
    }

    public void SetMaster(float masterSliderPosition) {
        var volume = Mathf.Clamp(Mathf.Log10(masterSliderPosition / 5) * 20f, -80f, 0f);
        audioMixer.SetFloat("Master", volume);
        if (masterSlider != null) {
            masterSlider.value = masterSliderPosition;
            ES3.Save<float>("MASTER_SLIDER", masterSlider.value);
        }
    }
}

3.SliderInitializer

音量を調節するSliderにアタッチして使います。
シーン遷移時にSliderが非アクティブな場合、アクティブになったときにAudioVolumeから音量のデータを読み込んで、音量3なら3の位置にSliderが移動します。

using UnityEngine;
using UnityEngine.UI;

//ボリュームスライダーにアタッチして使用
//AudioVolumeクラスのスライダーを更新する

public class SliderInitializer : MonoBehaviour {
    public enum SliderType { BGM, SE, Voice, Master }
    public SliderType type;  // インスペクタから設定するスライダーのタイプ
    private Slider slider;   // このコンポーネントがアタッチされているスライダー

    void Awake() {
        slider = GetComponent<Slider>();
    }

    void OnEnable() {
        // スライダーが有効になるたびに、AudioVolumeのインスタンスと同期させる
        if (AudioVolume.i != null) {
            switch (type) {
                case SliderType.BGM:
                    AudioVolume.i.bGMSlider = slider;
                    slider.value = AudioVolume.i.GetMixerVolume("BGM");
                    break;
                case SliderType.SE:
                    AudioVolume.i.sESlider = slider;
                    slider.value = AudioVolume.i.GetMixerVolume("SE");
                    break;
                case SliderType.Voice:
                    AudioVolume.i.voiceSlider = slider;
                    slider.value = AudioVolume.i.GetMixerVolume("Voice");
                    break;
                case SliderType.Master:
                    AudioVolume.i.masterSlider = slider;
                    slider.value = AudioVolume.i.GetMixerVolume("Master");
                    break;
            }
            AudioVolume.i.AddListener();
        }
    }
}

2.注意事項

Sliderの「値の変更時(Single)」を以下の画像を参考に変更します。AudioVolume.SetBGMあるいはAudioVolume.SetSEが正しい。AudioVolume.SetBGM(float)あるいはAudioVolume.SetSE(float)は間違いなので注意!

3.参考記事

この記事が気に入ったらサポートをしてみませんか?