【Unity】サウンドテスト画面を作る - その2

f:id:amayoshitqs:20200930001253p:plain

Unityでサウンドテスト画面を作る第2回です。
マウスやタッチ操作ではない、キーボード(パッド)オンリーなのがミソです。

今回は「SE再生」を実装していきます。

前回はこちら。 amayoshitqs.hatenablog.com

SE再生を実装する前に

とは言うものの、まずはソースコードを少し修正しましょう。
前回はBGMしか無かったのでenumや変数に「Audio~」「Sound~」という名称を使っていましたが、
今回SEを追加するにあたり、名称でも区別できるようにしましょう。

public enum BgmList
{
    BGM00,
    BGM01,
    BGM02
}

SoundListBgmListに修正。

[SerializeField] AudioSource bgmSource;

audioSourcebgmSourceに修正。

以上です、参照している箇所の修正までお忘れなく。
IDEの機能で参照ごと変更できると楽ですね。

SEを再生しよう

f:id:amayoshitqs:20200929231635p:plain

ではResources/Audio/に効果音ファイルを入れましょう。
数が多くなるとBGMとSEで分けた方が良いかなと思いますが、今回は実装優先ということで。

f:id:amayoshitqs:20200929232021p:plain

続いてAudioSourceですが、1つのGameObjectに複数の同じコンポーネントを付けると管理が面倒になるので、
画像のようにSoundManagerに子オブジェクトを2つぶらさげる形にしましょう。

f:id:amayoshitqs:20200929232241p:plain

このように2つの子オブジェクトにAudioSourceを付けます。
元々SoundManagerに付けていたAudioSourceは消してください。
SEの方はLoopをOffにしておくとイイと思います。

ではここからスクリプトに移ります。

public enum SeList
{
    SE00,
    SE01,
    SE02
}

効果音のenumになります。
先ほどResources/Audio/に追加したファイル名と同じにしてください。

続いてメンバ変数。

public class SoundManager : MonoBehaviour
{
    [SerializeField] EventSystem eventSystem;
    [SerializeField] Slider bgm;
    [SerializeField] Text bgmText;
    [SerializeField] Text bgmNumberText;
    [SerializeField] Slider se; // 追加
    [SerializeField] Text seText; // 追加
    [SerializeField] Text seNumberText; // 追加
    [SerializeField] Slider exit;
    [SerializeField] Text exitText;
    [SerializeField] AudioSource bgmSource;
    [SerializeField] AudioSource seSource; // 追加
    int bgmLength;
    int seLength; // 追加
    GameObject go;
}

分けて書くとややこしくなるので追加部分を明瞭にする感じで。
次はStart()メソッド

void Start()
{
    bgmLength = Enum.GetNames(typeof(BgmList)).Length;
    bgm.maxValue = bgmLength;
    bgm.minValue = -1;

    seLength = Enum.GetNames(typeof(SeList)).Length; // 追加
    se.maxValue = seLength; // 追加
    se.minValue = -1; // 追加

    OnChangeBGM(0);
    OnChangeSE(0); // 追加

    eventSystem.SetSelectedGameObject(bgm.gameObject);
}

ここはBGMと全く同じですね。
今回もOnChangeSE()は後述します。

更に続いてUpdate()メソッド

void Update()
{
    var current = eventSystem.currentSelectedGameObject;

    if(current != go)
    {
        OnChangeMenu(current);
        go = eventSystem.currentSelectedGameObject;
    }

    if(Input.GetKeyDown(KeyCode.Z))
    {
        if(current == bgm.gameObject)
        {
            BgmList music = (BgmList)bgm.value;
            bgmSource.clip = Resources.Load<AudioClip>("Audio/" + music.ToString());
            bgmSource.Play();
        }
        // 追加開始 //
        else if(current == se.gameObject)
        {
            SeList sound = (SeList)se.value;
            AudioClip clip = Resources.Load<AudioClip>("Audio/" + sound.ToString());
            seSource.PlayOneShot(clip);
        }
        // 追加終了 //
        else if(current == exit.gameObject)
        {
            bgmSource.Stop();
            SceneManager.LoadScene("Title");
        }
    }
}

こちらはZキーを押した時の挙動の部分だけ追加します。
ループさえしなければ再生方法は同じでも良いのですが、折角なのでSEはSEらしくPlayOneShot()を使いましょう。

お次は文字の明暗を決めていたOnChangeMenu()メソッド。

void OnChangeMenu(GameObject current)
{
    bgmText.color = current == bgm.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f);
    bgmNumberText.color = current == bgm.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f);
    seText.color = current == se.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f); // 追加
    seNumberText.color = current == se.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f); // 追加
    exitText.color = current == exit.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f);
}

こちらはBGMと同じです。
コピペして変数だけ変えちゃいましょう。

最後にOnChangeSE()メソッドです。

public void OnChangeSE(float value)
{
    if(value == seLength)
    {
        se.value = 0;
    }
    if(value == -1)
    {
        se.value = seLength-1;
    }

    seNumberText.text = se.value.ToString("00");
}

これもBGM版と同じです。

スクリプトの修正は以上になります。
続いてインスペクタでゲームオブジェクトを用意します。

f:id:amayoshitqs:20200929235603p:plain f:id:amayoshitqs:20200929235631p:plain

このようにBGMと同じ構成でSEのオブジェクトを生成し、レイアウトを調整してください。
そして各種SliderのNavigationExplicitであり、Select On Up/Downが正しいものを指してあるか確認します。

f:id:amayoshitqs:20200929235902p:plain

最後にSoundManagerに各オブジェクトをドロップします。

完成

f:id:amayoshitqs:20200930001253p:plain

BGMとは別にSEを選択して再生することができると思います。
本来サウンドテストはBGMを鳴らしながらSEを鳴らし、音量が適正かどうかを確かめるものなので分割はマストですね。

次回に向けて微調整

SE追加だけでも記事にすると長くなってしまったので今回はここまでです。
しかし次回に向けて(次回の説明を省くために)以下の修正を行っていただきます。

SoundConstants.csというファイルを作り、内容を以下のようにします。
代わりにSoundManager.csからenumの定義を除去して下さい。

public enum BgmList
{
    BGM00,
    BGM01,
    BGM02
}

public enum SeList
{
    SE00,
    SE01,
    SE02
}

public class SoundConstants
{
}

今後こちらでサウンド関係で使う定数を定義したりする時に使います。

今回のソースコード

using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SoundManager : MonoBehaviour
{
    [SerializeField] EventSystem eventSystem;
    [SerializeField] Slider bgm;
    [SerializeField] Text bgmText;
    [SerializeField] Text bgmNumberText;
    [SerializeField] Slider se; // 追加
    [SerializeField] Text seText; // 追加
    [SerializeField] Text seNumberText; // 追加
    [SerializeField] Slider exit;
    [SerializeField] Text exitText;
    [SerializeField] AudioSource bgmSource;
    [SerializeField] AudioSource seSource; // 追加
    int bgmLength;
    int seLength; // 追加
    GameObject go;

    void Start()
    {
        bgmLength = Enum.GetNames(typeof(BgmList)).Length;
        bgm.maxValue = bgmLength;
        bgm.minValue = -1;

        seLength = Enum.GetNames(typeof(SeList)).Length; // 追加
        se.maxValue = seLength; // 追加
        se.minValue = -1; // 追加

        OnChangeBGM(0);
        OnChangeSE(0); // 追加

        eventSystem.SetSelectedGameObject(bgm.gameObject);
    }

    void Update()
    {
        var current = eventSystem.currentSelectedGameObject;

        if(current != go)
        {
            OnChangeMenu(current);
            go = eventSystem.currentSelectedGameObject;
        }

        if(Input.GetKeyDown(KeyCode.Z))
        {
            if(current == bgm.gameObject)
            {
                BgmList music = (BgmList)bgm.value;
                bgmSource.clip = Resources.Load<AudioClip>("Audio/" + music.ToString());
                bgmSource.Play();
            }
            // 追加開始 //
            else if(current == se.gameObject)
            {
                SeList sound = (SeList)se.value;
                AudioClip clip = Resources.Load<AudioClip>("Audio/" + sound.ToString());
                seSource.PlayOneShot(clip);
            }
            // 追加終了 //
            else if(current == exit.gameObject)
            {
                bgmSource.Stop();
                SceneManager.LoadScene("Title");
            }
        }
    }

    void OnChangeMenu(GameObject current)
    {
        bgmText.color = current == bgm.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f);
        bgmNumberText.color = current == bgm.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f);
        seText.color = current == se.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f); // 追加
        seNumberText.color = current == se.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f); // 追加
        exitText.color = current == exit.gameObject? new Color(0, 0, 0, 1) : new Color(0, 0, 0, 0.5f);
    }

    public void OnChangeBGM(float value)
    {
        if(value == bgmLength)
        {
            bgm.value = 0;
        }
        if(value == -1)
        {
            bgm.value = bgmLength-1;
        }

        bgmNumberText.text = bgm.value.ToString("00");
    }

    public void OnChangeSE(float value)
    {
        if(value == seLength)
        {
            se.value = 0;
        }
        if(value == -1)
        {
            se.value = seLength-1;
        }

        seNumberText.text = se.value.ToString("00");
    }
}