目的
- SEを重ねて鳴らすにはAudioSourceをSEの数だけ用意しなければならないけどいちいち準備するのは面倒
- BGMの操作をいちいちaudioSource変数を介してするのは面倒
などがあったので、BGMとSEをまとめて管理するクラスを作成しました。
作成したクラス
概要
- BGMに関してはAudioSourceをはじめから用意しておき、それをスクリプトで使用するようにしました(重ねて鳴らすのはこのクラスでは不可)。
- SE用のAudioSourceはSEを鳴らす処理を呼び出したときに割り当てる。すべてのAudioSourceが使用中の場合は新たに生成する(重ねて鳴らせる)。
- ポーズ画面なども想定してSEはまとめて一時停止できるようにした。
各関数の役割は次の表のとおり。AudioSourceの関数などを利用していますが、分からなかったらこちらの記事を参考にしてください(Unity 音楽の再生(再生・停止、5秒移動、再生速度の変化など) - ミドリ黄のプログラミングメモノート)。
PlayBGM(AudioClip) | 引数に音源を設定し、BGMを鳴らす。 |
---|---|
PauseBGM() | BGMを一時停止する |
UnPauseBGM() | ↑で一時停止したBGMを再開する。 |
PlaySE(AudioClip clip) | 引数に音源を設定し、SEを鳴らす。SEを鳴らしているAudioSourceが返り値となっているため、SEごとに操作をしたい場合はこれを使う。 |
PauseAllSE() | すべてのSEを止める。ポーズ画面などに使用。 |
UnPauseAllSE() | すべてのSEを再開。ポーズ画面から戦闘に戻った時などに使用。 |
ソースコード
using System.Collections.Generic; using UnityEngine; using System.Linq; public class AudioPlayer : MonoBehaviour { //BGM用のオーディオソース [SerializeField] protected AudioSource bgmAudioSource; //SE用のオーディオソース List<AudioSource> seAudioSources = new List<AudioSource>(); //シングルトンにすることでアクセスを容易にしている public static AudioPlayer I { get; private set; } private void Awake() { I = this; } //BGMを最初から鳴らす public void PlayBGM(AudioClip clip) { bgmAudioSource.clip = clip; bgmAudioSource.Play(); } //BGMを一時停止 public void PauseBGM() { bgmAudioSource.Pause(); } //BGMを再開する public void UnPauseBGM() { bgmAudioSource.UnPause(); } //SEを鳴らす public AudioSource PlaySE(AudioClip clip) { //鳴らしていないAudioを順に探す var a = seAudioSources.FirstOrDefault(s => !s.isPlaying); //無かったら新しく追加する if (a == null) { //新たなゲームオブジェクトを作成して、子オブジェクトとして追加する GameObject obj = new GameObject(""); obj.transform.SetParent(transform); //生成したobjにAudioSourceを追加して、リストに追加 a = obj.AddComponent<AudioSource>(); seAudioSources.Add(a); } //clipを設定 a.clip = clip; //鳴らす a.Play(); return a; } //すべてのSEを一時停止 public void PauseAllSE() { foreach (var s in seAudioSources) { s.Pause(); } } //すべてのSEを再開する public void UnPauseAllSE() { foreach (var s in seAudioSources) { s.UnPause(); } } }
使用例
オブジェクトの準備
「Create Empty」で空のオブジェクトを用意したら先ほどのスクリプトとAudioSourceをアタッチします。
操作用スクリプトの用意
次に操作用のスクリプトを用意したので、これを適当なゲームオブジェクトにアタッチします。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Sample : MonoBehaviour { //音源 [SerializeField] AudioClip bgm1;//BGM1 [SerializeField] AudioClip bgm2;//BGM2 [SerializeField] AudioClip se1;//SE1 [SerializeField] AudioClip se2;//SE1 AudioSource as1; AudioSource as2; void Update() { //SEについての処理 //Qを押すとSE1を最初から鳴らす if (Input.GetKeyDown(KeyCode.Q)) { as1 = AudioPlayer.I.PlaySE(se1); } //Wを押すとSE1を停止 else if (Input.GetKeyDown(KeyCode.W)) { as1?.Stop(); } //Eを押すとSE2を最初から鳴らす else if (Input.GetKeyDown(KeyCode.E)) { as2 = AudioPlayer.I.PlaySE(se2); } //Rを押すとSE2を停止 else if (Input.GetKeyDown(KeyCode.R)) { as2?.Stop(); } //Tを押すとすべてのSEを一時停止 else if (Input.GetKeyDown(KeyCode.T)) { AudioPlayer.I.PauseAllSE(); } //Yを押すとすべてのSEを再開 else if (Input.GetKeyDown(KeyCode.Y)) { AudioPlayer.I.UnPauseAllSE(); } //ここからBGMについての処理 //Aを押すとBGM1を鳴らす else if (Input.GetKeyDown(KeyCode.A)) { AudioPlayer.I.PlayBGM(bgm1); } //Sを押すとBGM2を鳴らす else if (Input.GetKeyDown(KeyCode.S)) { AudioPlayer.I.PlayBGM(bgm2); } //Dを押すとBGMを一時停止 else if (Input.GetKeyDown(KeyCode.D)) { AudioPlayer.I.PauseBGM(); } //Fを押すとBGMを再開 else if (Input.GetKeyDown(KeyCode.F)) { AudioPlayer.I.UnPauseBGM(); } } }