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

f:id:amayoshitqs:20200930230547p:plain

Unityでサウンドテスト画面を作る第3回です。
マウスやタッチ操作でなく、キーボードやゲームパッドで動作させるクラシックタイプにアプローチします。

今回は「再生中のBGMタイトル表示」の機能を作っていきます。
そしてこの機能は2つのプロセスを提案してみます。

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

UI配置

f:id:amayoshitqs:20200930221308p:plain f:id:amayoshitqs:20200930221228p:plain

  • 「NowPlaying:」と固定表示するText
  • 曲名を表示するText

の2つのオブジェクトで構成します。

パターンA・enumそのまま

BGMリストのenum名(ファイル名)をそのまま文字列変換して表示します。
超簡単ですが柔軟性がなく、空白などを入れることもできません。

まずはメンバ変数。

[SerializeField] Text nowPlayingTitleText;

Hierarchyの「NowPlayingTitle」オブジェクトを参照する変数です。

続いてStart()メソッド。

void Start()
{
    nowPlayingTitleText.gameObject.SetActive(false); // 追加

    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が再生されていないので曲名を隠すようにします。
今回はオブジェクトを非アクティブにすることにしました。

お次は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();
            
            nowPlayingTitleText.gameObject.SetActive(true); // 追加
            nowPlayingTitleText.text = music.ToString(); // 追加
        }
        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");
        }
    }
}

BGM再生時にゲームオブジェクトをアクティブにし、曲名を代入します。
enumToString()でそのまま文字列に変換しています。
まぁ既にResources.Loadで同じことしてますけど。

はい、なんと以上です。

パターンA完成

f:id:amayoshitqs:20200930224159p:plain

曲を再生するごとにNowPlaying:の横の文字が切り替わります。

至極簡単に実装できましたが、やはりファイル名として適した名前しか使えないのは不便ですね。
Hello World」みたいにスペースを含めたり、
「地上コース」みたいな日本語を使うのも難しくなります。

では、曲ごとに固有のタイトルを付けられるようにしましょう!

パターンB・辞書を作って固有定義

C#Dictionaryを使って1曲1曲名前を付けましょう。
前回最後に作った「SoundConstants.cs」SoundConstantsクラスで定義していきます。

public static class SoundConstants
{
    public static readonly Dictionary<BgmList, string> BgmDictionary = new Dictionary<BgmList, string>()
    {
        { BgmList.BGM00, "Queen" },
        { BgmList.BGM01, "炎のロックンロール" },
        { BgmList.BGM02, "Keep Yourself Alive" }
    };
}

このように「BgmListとstringのDictionary」を作り、それぞれに個別で文字列を定義していきます。
どこからでも参照できるようにstaticでpublicなクラスおよび変数にする必要があります。

曲名が書けたら「SoundManager.cs」のUpdate()メソッドを修正しましょう。

// nowPlayingTitleText.text = music.ToString(); // 修正前
nowPlayingTitleText.text = SoundConstants.BgmDictionary[music]; // 修正後

辞書を参照して曲名を表示するようにしました。

パターンB完成

f:id:amayoshitqs:20200930230547p:plain

このようになりました。
これなら空白も日本語も使い放題です。

ここから曲を再生してない時は「NowPlaying:」も消したい、などの改良はお好みでお願いします。

余談(雑談)

今回で必要最低限の機能が揃ったと思います。
フリー素材ならともかく、オリジナルの楽曲を使用しているゲームでサウンドテストを作るならここまでは欲しいですね。

残りはBGMとSEそれぞれのボリューム調節でしょうか。
機能的にもSliderの真価発揮ですね!
勿論AudioMixer経由での実装を行います、サウンドテストだけのボリューム調節じゃ意味無いですからね!

今回のソースコード

SoundManager.cs

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] Text nowPlayingTitleText; // 追加
    [SerializeField] AudioSource bgmSource;
    [SerializeField] AudioSource seSource;
    int bgmLength;
    int seLength;
    GameObject go;

    void Start()
    {
        nowPlayingTitleText.gameObject.SetActive(false); // 追加

        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();
            
            nowPlayingTitleText.gameObject.SetActive(true); // 追加
            // nowPlayingTitleText.text = music.ToString(); // 修正前
            nowPlayingTitleText.text = SoundConstants.BgmDictionary[music]; // 修正後
        }
        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");
    }
}

SoundConstants.cs

using System.Collections.Generic;

public enum BgmList
{
    BGM00,
    BGM01,
    BGM02
}

public enum SeList
{
    SE00,
    SE01,
    SE02
}

public static class SoundConstants
{
    public static readonly Dictionary<BgmList, string> BgmDictionary = new Dictionary<BgmList, string>()
    {
        { BgmList.BGM00, "Queen" },
        { BgmList.BGM01, "炎のロックンロール" },
        { BgmList.BGM02, "Keep Yourself Alive" }
    };
}