【Unity】1つのオブジェクトでBGMとSEを再生してみる

スポンサーリンク

今回はUnityでのBGMとSEを鳴らす処理を試してみたいと思います。

正直なところ、SEを鳴らす、BGMを鳴らすはあちこちに記事があると思います。
では、BGMを流しつつ、SEも鳴らすにはどうすれば良いのでしょうか?
シンプルなのは、BGM用のオブジェクトとSE用のオブジェクトを作成して、それぞれにAudioSourceを割り当てる方法でしょうか。
3Dの場合は、SE用のオブジェクトというよりは、音のなるオブジェクトにAudioSourceを割り当てて、SEを鳴らすのが立体音響として良いのだと思います。
ただ、2Dの場合は、そこまでやる必要が無いと思うので、1つのオブジェクトにまとめる事はできないのだろうか? と思ったので、その方法を軽く考えてみました。

結論としては、1つのオブジェクトに2つのAudioSourceを割り当てれば実現できます。

オブジェクトを用意

まずは、対象のシーンにEmptyObjectを作成します。(名前は適当に DebugScript としました。)
既にゲーム管理用のオブジェクトなどが存在するのなら、新しくEmptyObjectは作らずに、そのオブジェクトに対して以降の操作をすればOKです。

オブジェクトに2つのAudioSourceを追加

続いて、対象オブジェクトに AudioSource を2つ追加します。
そして、追加したどちらかの AudioSourceLoop にチェックを入れます。こちらがBGM用のAudioSourceになります。
BGMの方は基本的に音源をループ再生すると思うので、Loopを有効にしたのですが、『このチェックの有無でどちらがBGM用かを判別する』という意図もあります。

(上の画像は最終的な状態なので、Scriptも付与されています。あと、ボタンも色々配置しています)

スクリプト作成

続いて、スクリプトを作成します。
適当にC# Scriptを作成して、対象のオブジェクトに割り当てましょう。
(今回は、適当に DebugScript という名前でスクリプトを作成しました)
スクリプトの内容は以下になります。(重要な部分は、Startメソッド内の記述です)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DebugScript : MonoBehaviour
{
    [SerializeField] private AudioClip audioBGM1;
    [SerializeField] private AudioClip audioBGM2;
    [SerializeField] private AudioClip audioSE1;
    [SerializeField] private AudioClip audioSE2;

    private AudioSource audioSourceBGM;
    private AudioSource audioSourceSE;
    private float audioBGMVolume = 0.1f;
    private float audioSEVolume = 0.5f;

    void Start()
    {
        foreach (AudioSource audioSource in GetComponents<AudioSource>())
        {
            if (audioSource.loop) {
                // BGM用AudioSource
                audioSourceBGM = audioSource;
                audioSourceBGM.volume = audioBGMVolume; // BGM音量設定
                Debug.Log("Find BGM AudioSource");
            }
            else
            {
                // SE用AudioSource
                audioSourceSE = audioSource;
                audioSourceSE.volume = audioSEVolume; // SE音量設定
                Debug.Log("Find SE AudioSource");
            }
        }
    }
    // BGM1を再生
    public void OnClickPlayBGM1()
    {
        audioSourceBGM.clip = audioBGM1;
        audioSourceBGM.Play();
    }
    // BGM2を再生
    public void OnClickPlayBGM2()
    {
        audioSourceBGM.clip = audioBGM2;
        audioSourceBGM.Play();
    }
    // BGMを停止
    public void OnClickStopBGM()
    {
        audioSourceBGM.Stop();
    }
    // SE1を再生
    public void OnClickPlaySE1()
    {
        audioSourceSE.PlayOneShot(audioSE1);
    }
    // SE2を再生
    public void OnClickPlaySE2()
    {
        audioSourceSE.PlayOneShot(audioSE2);
    }
}

あとは適当に…

私は、確認用にSEとBGMをそれぞれ2種類用意して、ボタンで再生制御できるようにしました。
ClipをGUI上で割り当てたり、ボタンのクリックイベントの割り当てをしたり……
必要に応じて対応して下さい。

軽くスクリプト説明

今回のポイントは Startメソッド内の記述 です。
GetComponents<AudioSource>でオブジェクトに付与されているAudioSourceを全て取得。
そして、foreachで取得したAudioSourceをBGM用かSE用か判別して保持します。
if (audioSource.loop)がその判定部分ですね。
AudioSourceを追加した時に片方だけLoopをONにしているので、ONになっている方がaudioSorceBGM、もう1つがaudioSourceSEとして保持されます。
あとは、必要に応じて、Playだったり、PlayOneShotだったりを呼べば再生されます。

スポンサーリンク

まとめ

今回はBGMとSEの再生を1つのオブジェクトで完結させる事を試してみました。
ポイントはAudioSourceを複数追加して、GetComponents<AudioSource>で取得して、使い分ける事です。
今回はLoopをONにしている方をBGMとしましたが、1つ目に見つかった方をBGM用と決めても問題ありません。

特に何も工夫した部分はありませんが、この記事が何かのお役に立てたら嬉しいです。

スポンサーリンク