【Unity】BGMやSEをスライダーで調整したい

対象 Unity初心者

書いている人 書いてる時点でUnity学習3ヶ月目 プログラミング歴1年

前提  Unityでの基本操作がわかる

環境 M1Mac
Unity2019.4.17f1

参考 http://tsubakit1.hateblo.jp/entry/2017/06/13/235900#fn-8a06f46f

音源 効果音ラボ 魔王魂

Unityでゲームを作る時、BGMやSE(サウンド音)が必要になってくると思う。これを実装するのはそんなに難しくはないが、よくゲームに実装されているBGMやSEをスライダーで調整する機能を取り入れると難しかったので、これをまとめてみる。他のやり方で実装する方法もあると思うので参考程度に見てほしい。

主に、参考欄に貼ったテラシュールブログさんの記事を参考に実装してます。
また、記事内では2Dプロジェクトで作成してます。

目次

BGMとSEを設定する

まずは、スライダーを設定する前にBGMとSEを設定してみる。余裕のある人は、以下の手順で実際に手を動かしてみてほしい。

音源をAssets以下に入れておく

BGMやSEをフリーサイトからあらかじめ取得しておこう。取得したらBGMフォルダをAsset内に作成してその中に落としてきた音源を突っ込んでおく。

素材をUnityの中に入れておく。

BGMを設定する

次にUnityのプロジェクトを立ち上げて、BGMを流す用のオブジェクトを作成する。

空のGameObjectを作成して、BgmManagerとでも名付けておこう。

BgmManagerが作成できたら、今度はAudioSourceコンポーネントをそのオブジェクトにくっつけよう。

Audio Sourceコンポーネントをアタッチ

このAudioSourceコンポーネントAudioClipに流したい曲をくっ付けるだけで、もうゲームでBGMを流すことができる。

魔王魂さんからとってきたBGMをくっつける。

試しにPlayボタンを押してみよう。おそらく設定したBGMが流れるはずだ。

SEを設定する

SEとは、サウンドエフェクトの略でボタンを押した時に、ピコッってなったりする効果音のことだ。これも設定していこう。

今回は、ボタンをクリックしたら音が出るといったような感じにしたいので、まずはボタンを作成する。

UIからButtonを選択
適当にTextを変更

「ボタンを押したら〜」って実装をしたい場合は、ButtonコンポーネントのOnClick()の部分に設定をしていく。

OnClick()のとこに何をつければいいんだ?

このOnClick()の部分にサウンドを設定したい。その為に、SE用のオブジェクトを新しく作成しよう。空のGameObjectを作ってSEManagerとでもしておこう。

名前をSEManagerとした。

そしたら、これにまたAudioSourceコンポーネントをくっ付ける。

Bgmと同じ容量だ。

そして、AudioClipの欄にSEを設定する、、、と思いきやSEの場合はそうではない。SEの場合はとりあえず何も設定しなくていい。ただ、AudioSourceコンポーネントをくっ付ければいいだけだ。

出来たら、ButtonのOnClick()に戻って、そこにSEManagerを突っ込もう。

Noneのところに、、
さっき作ったSEManagerを突っ込む。

突っ込んだら、No Functionとなっている部分から、AudioSource→PlayOneShot(AudioClip)を選択する。

PlayOneShot(AudioClip)を呼び出す

ここで何をやっているかというと、AudioSourceクラスのPlayOneShotメソッドを呼び出している。

なぜ、AudioSourceクラスを呼べるかというと、SEManagerにAudioSourceコンポーネントがくっついているからだ。このAudioSourceコンポーネントを通して、PlayOneShotを呼んでいる。

PlayOneShotメソッドは1回だけ音を鳴らすメソッドで、このメソッドに音源を設定していく。

このNoneの部分に鳴らしたいSE音を設定する
好きなSE音を設定しよう。

音源を設定したら、再生してから実際にボタンをクリックして音を鳴らしてみよう。おそらく1回音がなるはずだ。


ちょっとこのSEのところを整理してみよう。

  1. 空のGameObjectを作り、AudioSourceコンポーネントをくっつける。(ここではSEManager)
  2. Buttonオブジェクトを作成して、そこのOnClick()部分に、SEmanagerを突っ込む。
  3. Functionの部分にPlayOneShotを設定する
  4. AudioClipに再生したいSEを設定する

こんなところだろうか。途中意味がわからなくても、実際に手を動かせばそのうち意味もわかってくるはずなので、まずは試しに作ってみてください。

Buttonをもう一つ作成してSEを設定する

BGMと違ってSE音は色々なところで使うはずだ。ボタンはおそらく1つじゃなく複数あるだろうし、このボタンでは違うSE音を鳴らしたい等必要に応じてSE音を変更しなくてはならない。これの実装もわりと簡単なので、以下の手順に沿ってやってみよう。

HierarchyにButtonをもう1つ作成する。

わかりやすいように前のボタンをButton1とした。新しく作ったのはButton2
Button2を作成

ButtonコンポーネントのOnClickに上で作ったSEManagerをアタッチ。
上と同様の手順でPlayOnShotを呼び出して、SEに好きな音源を設定するだけだ。

今度は新しいSEをくっつけた。

これで再生すると、Button1と2にはそれぞれ設定した音がボタンを押すたびに聞こえるはずだ。

つまりはAudioSourceコンポーネントがついたGameObjectを一つ用意しておくだけで、それを通してさまざまなオブジェクトにSEを設定できる。
そして、これのVolumeを変更していくことで、全体のSEの音量を変更していくことができるようになるというわけだ。(この部分がSliderを動かして音を変更する本記事の目的に繋がる)


ちなみに、なぜ音が聞こえるかと言うと、MainCameraに元々AudioLisnerコンポーネントがくっついているおかげだったりする。これのチェックを外すと音が消えるので確かめてみてほしい。

MainCameraについてるAudioListenerから曲が流れてくるぞ。

【応用】Prefabにしたボタンにはどうやって音を設定するのか?

ここで一つ自分が詰まってしまったものを紹介する。やらない人は結構長いので飛ばしてもOK。(本当はこれを自分用にまとめておきたかったのが目的だったりもする。)
既にHierarchy上にあるボタンにはOnClick()からSEManagerをくっ付けることができた。
ただ、何らかの操作をしてから生成したボタンなどのオブジェクトにはどうやってSEを設定すればよいだろうか。

普通にOnClick()にSEManagerをくっ付ければよくないか?と思うかもしれないが、PrefabにしてしまうとSEManagerをくっ付けることができなくなる。

試しに、上で作ったボタンをPrefab化しよう。

Prefabフォルダを作成して、そこにButton1をD&D(ドラッグ&ドロップ)だ。
Prefab化するとHierarchyのオブジェクトは青くなる。

元々、Button1のOnClick()上には、SE音が設定されていたはずだ。ただ、Button1のPrefabを開くと、そこにSEは設定されていない。(Hierarchy上のButton1には設定されたままです。このButton1は使わないので削除してください。)

OpenPrefabからButton1のPrefabを開くとそこのOnClickはNoneになっている。

これでは、このボタンをInstantiateしたとしても、OnClick()に音が設定されていないのでSE音が鳴らない。どうしたものかと詰まって検索したところ、こちらの記事で解決できた。今回はこの記事に沿って、PrefabにもSEを設定する。

こうすることで、SEManagerのVolumeを変更すれば、PrefabのSEもPrefabじゃないSEも一括で音量変更ができるようになる。

その解決方法を見ていこう。自分もよくわかってない用語ややり方もあるのでそこは理解次第追記予定です。

ScriptableObjectを作成する

いきなりわからん単語が出てきた。ScriptableObjectのことをイマイチわかってないけど、とりあえずこいつはGameObjectにはくっつけないものらしい。詳しくはググってみてください。

新規に C#スクリプトを作成して、SEManagerという名前をつけて以下の用に記述しよう。

新しくスクリプトを作成する。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class SEManager : ScriptableObject
{
	public AudioSource audioSource{ get; set; }

	public void PlayOneShot(AudioClip clip)
	{
		if (audioSource != null)
		{
			audioSource.PlayOneShot(clip);
		}
	}
}

わからないなりにも、ポイントだけ見ていく。

まずは継承。ScriptableObjectはGameObjectにくっつけるわけではないので、:MonoBehaviorではなく:ScriptableObjectを継承しよう。

そして、[CreateAssetMenu]をクラスの定義の上に記述する。これを書くと、Projectの+ボタンからScriptableObjectのアセットを作ることができる。(自分は、「クラスのインスタンス」的な意味で解釈してるけどあってるかしら)

[CreateAssetMenu]を書くことで、Projectに表示されるようになる。

このScriptableObjectのアセットを通して、PrefabのOnClick()にも音を設定できるようにしていく。

残りのコード部分、public AudioSource audioSource{ get; set; }は普通にプロパティで。public void PlayOneShot(AudioClip clip)はメソッドだ。

ScriptableObjectのアセットを生成する

ここまで出来たら実際にProjectの+ボタン→SE ManagerをクリックしてScriptableObjectのアセットを生成しよう。

生成されたらAssetsフォルダ以下にNew SE Managerと書かれたアセットが生成されるはずだ。

こいつがScriptableObjectのアセットだ。

インスペクタを見てみると、スクリプトに書いたプロパティも表示されてる。

これを生成して一体どうするんだ?

ButtonコンポーネントのOnClickにScriptableObjectのアセットをくっつける

ScriptableObjectのアセットが出来たらButtonの方に戻ろう。ButtonのPrefabを開いて、OnClick()からこのアセットを設定する。
そう、つまりは、このアセットを生成することで、PrefabのOnClick()にこれをくっつけることができるようになるのだ。

ButtonをOpenPrefabする
OnClick()にアセットファイルを設定。

アセットファイルを設定したら、SEManagerからPlayOneShotメソッドを呼び出す。あくまで、このメソッドはScriptableObject内で定義したメソッドで、AudioSourceコンポーネントから呼んできているものとは違うぞ。

FunctionにPlayOneShotを選択。このメソッドは以下の部分を呼び出してる。
//SEManager(ScriptableObject)の中のメソッド

public void PlayOneShot(AudioClip clip)
	{
		if (audioSource != null)
		{
			audioSource.PlayOneShot(clip);
		}
	}

SEを設定する

ScriptableObjectのファイルをアタッチし、PlayOneShotを選択したら、後はサウンドを設定しよう。

Noneのところに、、
鳴らしたいサウンドを設定する

ボタンPrefabをHierarchyに持っていき、再生する

設定し終わったら、ボタンPrefabを、Hierarchy上にD&Dしよう。そしたら、実際に再生してボタンをクリックして音が鳴るか確かめる。

PrefabのボタンをHierarchy上に持っていく。

ボタンをクリックして、、あれ?音が鳴らない。実はまだこれだけだと音を鳴らすことができない。なぜだかわかるだろうか?

それはScriptableObjectのpublic AudioSource audioSource;部分にaudioSourceコンポーネントが入っていないからである。ScriptableObject内のPlayOneShotメソッドでは、audioSourceのPlayOneShotを呼び出しいる。ただ、audioSource自体にはまだ何もつけていない。これを解決するのが以下の方法だ。

AudioSourceがNoneになっている。ここにAudioSorceのコンポーネントをいれたい。

MonoBehaviourEventTriggerスクリプトを作成する

新たにProject内からC#スクリプトを作成して、MonoBehaviourEventTriggerと名付けよう。これは、Hierarchy上のSEManagerオブジェクトにくっ付けるもので、

MonoBehaviourEventTriggerと名付ける。

ファイルが生成できたら、以下をコピペしよう。

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

public class MonoBehaviourEventTrigger : MonoBehaviour
{
	public UnityEvent onAwake = new UnityEvent();
	public UnityEvent onDestroy = new UnityEvent();

	void Awake()
	{
		onAwake.Invoke();
	}

	void OnDestroy()
	{
		onDestroy.Invoke();
	}
}

このスクリプトに書かれていることは正直全く理解していないが、とりあえずコピペしよう。

SEManagerオブジェクトにMonoBehaviourEventTriggerスクリプトをアタッチする

スクリプトができたら、それを「SEを設定する」で作成した、SEManagerオブジェクトにアタッチする。SEManagerオブジェクトはSEを管理するオブジェクトだ。このオブジェクトにMonoBehaviourEventTriggerをアタッチしよう。

AddComponentから、、
MonoBehaviourEventTriggerをアタッチ

OnAwake()にNewSEManagerアセットファイルを設定

MonoBehaviourEventTriggerがアタッチできたら、OnAwaka()にアセットファイルを設定する。

NewSEManagerアセットファイルをOnAwakeに設定する。

設定できたら、NoFunction→SEManager→AudioSource audioSourceを選択する。AudioSource audioSourceはメソッドじゃなくてプロパティだが、イベントに使用できるとのこと。(プロパティはフィールドを取得できるメソッドみたいなもの、フィールド・プロパティ・メソッドの概念が頭に入っていると理解しやすいかも)

audioSourceプロパティを選択

audioSourceプロパティを選択したら、AudioSourceをこれに入れてあげる。

OnAwake()はおそらく、SEManagerオブジェクトが生成されたら呼ばれるコールバック関数(ある関数が呼ばれた後に呼ばれる関数みたいなイメージ:ここではAwake関数が呼ばれた後に、OnAwakeが呼ばれている)みたいなもので、そのタイミングでプロパティにAudioSourceコンポーネントを突っ込んでいるという意味合いであってると思う。

これを行うことで、再生のタイミングで、ScriptableObjectのpublic AudioSource audioSource;部分にaudioSourceコンポーネントを突っ込むことができた。これで、Prefabから作成したボタンでも音がでるようになるはずだ。

実際に再生して確かめてほしい。

Sliderを作成する

いよいよこれから本題に入っていく。まずはSliderを作成しよう。
BGMとSE用に2本Sliderを用意するが、とりあえず最初はBGMから調整できるように設定していく。

UI→Sliderを選択
とりあえず1本Sliderを作成

Sliderを作ったら、インスペクタのSliderコンポーネントの中のValueを0から1に変更しておく。

Valueを0から、、
1に変更
Valueを0から1に変更すると、スライダーの丸が右側にきた。

これは、音量は最初からMax値で鳴らし、段々音を下げるようにするためだ。このValueを弄ることで音量を変更できるように設定する。

BgmMangerScriptを作成する

次にBgmManagerScriptを作成する。このスクリプトは、Bgmオブジェクトにくっ付ける用途のスクリプトでここで、上で作成したSliderを受け取って操作する。

BgmManagerを作成
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class BgmManager : MonoBehaviour
{
    public Slider slider;
    AudioSource audioSource;

    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        slider.onValueChanged.AddListener(value => this.audioSource.volume = value);
    }
}

sliderをアウトレット接続で受け取って、sliderのvalueがチェンジする度に、自身にくっついているaudioSourceコンポーネントのvolumeをいじっているっていう感じのスクリプトだ。

AddLisnerの中身はよくわからんけど、動けば問題ない。

BgmManagerスクリプトをアタッチする

BgmManagerスクリプトが出来たらそれをBgmオブジェクトにアタッチする。そして、Sliderを突っ込んであげる。これでBGMの音量が調整できるようになったはずだ。

Sliderをつっこむ
Sliderを動かせば、Volumeが変更された。

SEの方も同様の手順で行えば、音量の変更ができるぞ。

まとめ

一応、これでBGMとSEの音量をスライダーから変更することができた。特に、PrefabのOnClick()に音を設定する方法は難しかったと思う。今はまだわからなくてもそのうちわかるようになるはずだ。(自分に言い聞かせてます。)

たぶん他にももっとやり方があると思うんだが今の自分にはこれが精一杯なので、他のやり方を見つけたら別記事でまとめます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次