公開日:2023/07/08  更新日:2023/07/08

Unityでのサウンド管理

 Unityのゲーム制作ではBGMや効果音のサウンド管理を行っていく必要がある。
 やり方は色々あるが一例を紹介していく。またサウンド管理に役立つアセットについても紹介していく。
 AudioSourceなどオーディオ関係の基本操作がわからない場合は先に以下の記事を確認してほしい。
オーディオ設定の基本
 また、ScriptableObjectを使うのでわからない場合は以下の記事を確認してほしい。
ステータス管理
アイテム管理

Unityでのサウンド管理システム目次

サウンド管理システムの仕様
BGM管理システムの作り方
SE管理システムの作り方
目次にもどる

サウンド管理システムの仕様

 今回は3Dゲームを作る場合を想定してScriptableObjectを使ったサウンド管理システムを制作する。
 BGMについてはBGMを管理するゲームオブジェクトのAudioSourceから流す。
 効果音については、3D効果音と2D効果音を区別し、3D効果音(敵の足音・吠え声などを想定)については敵オブジェクトにAudioSourceを作成して流すようにする。一方で2D効果音(メニュー選択音などを想定)についてはBGMとほぼ同様の方法で流すようにしていく。

目次にもどる

BGM管理システムの作り方

 ScriptableObjectを使った以下のスクリプトを書く。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


[CreateAssetMenu(menuName = "Data/Create BGMData")]
public class bgmdata : ScriptableObject
{



    [SerializeField]
    private string BGMname; //BGMの名前
    [SerializeField]
    private AudioClip BGMClip; //BGMのAudioClipを指定。
    [SerializeField]
    [Range(0, 1)]
    private float BGMvolume; //BGMのボリューム




    //BGMのAudioClipを指定。
    public string GetBGMname()
    {
        return BGMname;
    }

    public AudioClip GetBGMClip()
    {
        return BGMClip;
    }

    public float GetBGMvolume()
    {
        return BGMvolume;
    }


}

 これでプロジェクトビューで右クリック→Create→Data→Create BGMDataと選択すればBGMのAssetファイルを作成できる。
 名前、指定するAudioClip、ボリュームの3つを記述可能。好きなだけAssetファイルを作ろう。


 続いてBGMのAssetファイルをデータベースとしてまとめられるようにしていく。新たなスクリプトを作成し以下のように記述しよう。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Data/Create BGMDataBase")]
public class bgmdatabase : ScriptableObject
{

    [SerializeField]
    private List<bgmdata> BGMLists = new List<bgmdata>();

    // BGMリストを返す
    public List<bgmdata> GetBGMLists()
    {
        return BGMLists;
    }

}

 このように記述することで、Create→Data→Create BGMDataBaseと作成することでデータベース用のAssetファイルを作れる。
 +マークを押すことで要素数を増やせる。先ほど作ったBGMdataのAssetファイルをドラッグアンドドロップして放り込んでセットする。


 呼び出したいBGMがあったら、そのBGMdataのBGMデータベースの要素番号を値渡ししつつ、PlayBGMのメソッド(後述する)を呼び出すようにする。呼び出し例は以下の通り。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Soundtest : MonoBehaviour
{



    [SerializeField] GameObject BGMkanriobject;
    BGMkanri BGMscript;


    void Start()
    {
        //このゲームオブジェクトのAudioSourceコンポーネントを取得。

        BGMscript = BGMkanriobject.GetComponent<BGMkanri>();

    }

    // Update is called once per frame
    void Update()
    {
        //マウス左ボタンが押されたなら・・
        if (Input.GetMouseButtonDown(0))
        {
            //AudioSourceコンポーネントからdragonsoundに指定したAudioClipを1回再生する。
            BGMscript.PlayBGM(0);

        }
    }
}

 シリアル化している。BGMkanriobjectには後述するゲームオブジェクト「BGMkanri」をセットする。
 今回はBGMdatabaseの0番のBGMdataを再生したいので、BGMscript.PlayBGM(0);と記述している。


 BGMkanriという空のゲームオブジェクトを作成し、AudioSourceをアタッチする。
 BGMはループさせたいので、AudioSourceのLoopにチェックをつける。


 BGMkanriに以下のようなスクリプト(名前はBGMkanri)をアタッチする。
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using VRM;

public class BGMkanri : MonoBehaviour
{

    [SerializeField] private bgmdatabase bgmDataBase;
    [SerializeField] private AudioSource audioSource;

    bgmdata BGMDATA;


    float MasterBGMvolume;




    // Start is called before the first frame update
    void Start()
    {
        //全体のボリューム。設定などで変更できるようにする予定
        //初期値を0.5fに設定
        MasterBGMvolume = 0.5f;
    }



    //どこからでもアクセス可能。返り値なし。
    public void PlayBGM(int Value)
    {

        //bgmdarabaseがnull以外なら処理。
        if (bgmDataBase != null)
        {


            //送られてきた値から、流したいbgmdataを取得しBGMDATAに代入する。
            BGMDATA = bgmDataBase.GetBGMLists()[Value];


            //再生するBGMDATAのaudioClipを指定。
            audioSource.clip = BGMDATA.GetBGMClip();


            //audioSourceのボリュームを指定。MasterBGMvolumeとBGMDATAのvolumeを掛け算した値にする。
            audioSource.volume = MasterBGMvolume * BGMDATA.GetBGMvolume();


            //再生する。
            audioSource.Play();

        }

    }
}
 シリアル化しているので、以下のようにBGMDataBaseと先ほどアタッチしたAudioSourceをドラッグ&ドロップして指定しておく。

 PlayBGMが呼び出されたら値渡しされた値を使ってBGMdataを取得し、再生するaudioClipやボリュームなどを指定して、再生する。

目次にもどる

SE管理システムの作り方

 SE管理システムもBGMと基本的な構造は同じ。
 ScriptableObjectを使った以下のスクリプトを書く。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Data/Create SEData")]
public class sedata : ScriptableObject
{



    [SerializeField]
    private string SEname; //効果音の名前
    [SerializeField]
    private AudioClip SEClip; //効果音のAudioClipを指定。
    [SerializeField]
    [Range(0, 1)]
    private float SEvolume; //効果音のボリューム
    [SerializeField]
    private bool SE3d; //効果音が3Dならtrue




    public string GetSEname()
    {
        return SEname;
    }

    public AudioClip GetSEClip()
    {
        return SEClip;
    }

    public float GetSEvolume()
    {
        return SEvolume;
    }

    public bool GetSE3d()
    {
        return SE3d;
    }

}

 BGMの時と同様にプロジェクトビューで右クリック→Create→Data→Create SEDataと選択することで効果音のAssetファイルを作れる。
 インスペクター欄で各項目を記述。異なるのはSE3dの項目を追加している点。trueであれば3D効果音、falseであれば2D効果音とする。


 効果音をまとめる効果音データベースを作るためのスクリプトを書く。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


[CreateAssetMenu(menuName = "Data/Create SEDataBase")]
public class sedatabase : ScriptableObject
{

    [SerializeField]
    private List<sedata> SELists = new List<sedata>();

    // 効果音リストを返す
    public List<sedata> GetSELists()
    {
        return SELists;
    }

}

 BGMの時と同様にプロジェクトビューで右クリック→Create→Data→Create SEDataBaseと選択することで効果音データベースのAssetファイルを作れるようになる。
 +マークを押して要素を増やし、作成した効果音のSEDataをドラッグ&ドロップして指定しよう。


 呼び出したい効果音があったら、そのSEdataのSEデータベースの要素番号を値渡ししつつ、ObjectSEとPlaySEのメソッド(後述する)を呼び出すようにする。呼び出し例は以下の通り。
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Soundtest2 : MonoBehaviour
{



    [SerializeField] GameObject SEkanriobject;
    SEkanri SEscript;


    void Start()
    {
        //このゲームオブジェクトのAudioSourceコンポーネントを取得。

        SEscript = SEkanriobject.GetComponent<SEkanri>();

    }

    // Update is called once per frame
    void Update()
    {
        //マウス左ボタンが押されたなら・・
        if (Input.GetMouseButtonDown(0))
        {

            SEscript.ObjectSE(this.gameObject);
            SEscript.PlaySE(0);

        }
    }
}

 シリアル化している。SEkanriobjectには後述するゲームオブジェクト「SEkanri」をセットする。
 SEscript.ObjectSE(this.gameObject);でこのゲームオブジェクトを値渡しする。
 続いて、SEdatabaseの0番のSEdataを再生したいので、SEscript.PlaySE(0);と記述している。


 SEkanriという空のゲームオブジェクトを作成し、AudioSourceをアタッチする(2D効果音管理用)。

 SEkanriに以下のようなスクリプト(名前はSEkanri)をアタッチする。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRM;

public class SEkanri : MonoBehaviour
{

    [SerializeField] private sedatabase seDataBase;
    [SerializeField] private AudioSource SE2DaudioSource;

    sedata SEDATA;

    GameObject seobject;


    float MasterSEvolume;

    AudioSource[] seAudioSource;




    // Start is called before the first frame update
    void Start()
    {
        //全体のボリューム。設定などで変更できるようにする予定
        //初期値を0.5fに設定
        MasterSEvolume = 0.5f;
    }

    //どこからでもアクセス可能。返り値なし。
    public void ObjectSE(GameObject SEobject)
    {
        //メソッドを呼び出したゲームオブジェクトを送り変数に代入。
        seobject = SEobject;

    }



    //どこからでもアクセス可能。返り値なし。
    public void PlaySE(int Value)
    {


        //sedarabaseがnull以外なら処理。
        if (seDataBase != null)
        {
            //送られてきた値から、流したいsedataを取得しSEDATAに代入する。
            SEDATA = seDataBase.GetSELists()[Value];



            //sedataから効果音が3D用なのか2D用なのか?
            if (SEDATA.GetSE3d())
                //ここから3Dの効果音処理

            {
        //呼び出し元ゲームオブジェクトのAudioSourceコンポーネントをGetComponentsでまとめて配列に代入
                seAudioSource = seobject.GetComponents<AudioSource>();

             //配列の要素数がゼロの場合・・・
                if (seAudioSource.Length == 0)
                {

                    //AudioSourceを10個作成する。
                    //15個あれば自分は困らないと思って15個にしているだけ
                    //3D効果音を使いまくるつもりなら増やしてもいい。

                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();
                    seobject.AddComponent<AudioSource>();

                    //AudioSource増やした状態で、今度こそ配列を作る。
                    seAudioSource = seobject.GetComponents<AudioSource>();
                }


                //配列0番から見ていく。
                for (int i = 0; i < seAudioSource.Length; i++)
                {

                    //配列i番のAudioSourceが再生中でないなら・・・
                    if (seAudioSource[i].isPlaying == false)
                    {
                        //spatialBlendを1にして3Dの音にする。
                        seAudioSource[i].spatialBlend = 1;


                        //配列i番のAudioSourceのvolumeにマスターボリュームとSEDATAのボリュームを掛け算した値を代入。
                        seAudioSource[i].volume = MasterSEvolume * SEDATA.GetSEvolume();

                        //配列i番のAudioSourceでSEDATAのAudioClipを1回再生する。
                        seAudioSource[i].PlayOneShot(SEDATA.GetSEClip());

                        //再生処理が終わったのでリターンして終了。
                        return;

                    }
                }

            }
            else
            {
                //ここから2D効果音の処理。

                //isPlayingは再生中ならtrue、再生していないならfalseを返す。
                if (SE2DaudioSource.isPlaying)
                {
                    //2D効果音は今回は同時に複数流すことは想定していない。よって再生中なら停止する。
                    SE2DaudioSource.Stop();
                }

                //送られてきた値から、流したいsedataを取得しSEDATAに代入する。
                SEDATA = seDataBase.GetSELists()[Value];

                //audioSourceのボリュームを指定。MasterSEvolumeとSEDATAのvolumeを掛け算した値にする。
                SE2DaudioSource.volume = MasterSEvolume * SEDATA.GetSEvolume();


                //SEDATAの/audioClipを再生する。
                SE2DaudioSource.PlayOneShot(SEDATA.GetSEClip());



            }

        }

    }
    
}
 シリアル化している。以下のようにSEのデータベースと2D効果音再生用AudioSourceをアタッチする。


 呼び出されたのが3D効果音だった場合には、このメソッドを呼び出したゲームオブジェクトにAudioSourceがあるかどうかを確認。ないならAudioSourceを15個作成する。
 3D効果音の場合は効果音が重なることも想定される。今再生中の効果音を止めてはならない。よってメソッドを呼び出したゲームオブジェクトのAudioSourceを全て取得して配列に代入している。そして、それらを一つずつisPlayingで再生中か調べて、再生中ではない場合に再生処理を行うようにしている。
 再生処理では、spatialBlendはデフォルトで0なので1にして3Dで音が流れるようにし、ボリュームの設定も行った後に再生を行っている。

 呼び出されたのが2D効果音だった場合には、SEkanriゲームオブジェクトにアタッチしたAudioSourceで音を流す。
 ボリュームを設定し、PlayOneShotでAudioClipを指定して再生している。

 おすすめのBGMや効果音のアセットは以下。
BGM・効果音のおすすめアセット

Unityのゲーム制作まとめへ戻る

page top