AudioManagerを仕上げてみました。
【前の記事】シングルトンの実装についてはこちら
→【Unity】なんちゃらManagerクラスを作ろう(シングルトン)
イメージ
自分がAudioManagerを作ろうって思った時点で思い描いた仕様はこんな感じ。- デザイナ上でBGMやSEを好きなだけセットできる。
- 好きな場所からいつでも再生、停止できる。
- 再生する音源は音声ファイル名で指定する。
- BGMは1つだけ再生。
- SEは指定した数まで同時再生可能。
実装
できました。ソースは長いので一番下に載せときました。
使い方
AudioManagerの配置
・空のGameObjectを作成・名前をAudioManagerとかにしとく
・AddComponentでAudioManagerを追加
追加直後の状態 |
AudioClipをセット
・mp3ファイルとかをHierarchyビューにドロップ(これでAudioClipができる)
・AudioClipの名前は分かりやすい名前にしておく
(呼び出すときに使うため)
・BGMListにAudioClipを好きなだけ追加
・SEListにAudioClipを好きなだけ追加
・MaxSEはSEの最大同時再生数です。好きな値で。
BGM2つ、SE3つセットしてみた所 |
テスト用スクリプト書いてみる
・MainCameraのAudioListenerを削除(or 無効化)・空のGameObjectにこんな感じのコンポーネントを付ける
using UnityEngine; public class script : MonoBehaviour { void OnGUI() { if(GUI.Button(new Rect(10,100,100,50),"BGM1")) { AudioManager.Instance.PlayBGM("bgm1"); } if(GUI.Button(new Rect(110,100,100,50),"BGM2")) { AudioManager.Instance.PlayBGM("bgm2"); } if(GUI.Button(new Rect(210,100,100,50),"BGMSTOP")) { AudioManager.Instance.StopBGM(); } if(GUI.Button(new Rect(10,200,100,50),"SE1")) { AudioManager.Instance.PlaySE("se1"); } if(GUI.Button(new Rect(110,200,100,50),"SE2")) { AudioManager.Instance.PlaySE("se2"); } if(GUI.Button(new Rect(210,200,100,50),"SE3")) { AudioManager.Instance.PlaySE("se3"); } if(GUI.Button(new Rect(310,200,100,50),"SESTOP")) { AudioManager.Instance.StopSE(); } } }実行!
BGMが鳴る!切り替えられる!停止できる!
SEが鳴る!いっぱい鳴る!
完璧っす。
ソース
AudioManager.cs
using UnityEngine; using System; using System.Linq; using System.Collections; using System.Collections.Generic; public class AudioManager : SingletonMonoBehaviour<AudioManager> { public List<AudioClip> BGMList; public List<AudioClip> SEList; public int MaxSE = 10; private AudioSource bgmSource = null; private List<AudioSource> seSources = null; private Dictionary<string,AudioClip> bgmDict = null; private Dictionary<string,AudioClip> seDict = null; public void Awake() { if(this != Instance) { Destroy(this); return; } DontDestroyOnLoad(this.gameObject); //create listener if(FindObjectsOfType(typeof(AudioListener)).All(o => !((AudioListener)o).enabled)) { this.gameObject.AddComponent<AudioListener>(); } //create audio sources this.bgmSource = this.gameObject.AddComponent<AudioSource>(); this.seSources = new List<AudioSource>(); //create clip dictionaries this.bgmDict = new Dictionary<string, AudioClip>(); this.seDict = new Dictionary<string, AudioClip>(); Action<Dictionary<string,AudioClip>,AudioClip> addClipDict = (dict, c) => { if(!dict.ContainsKey(c.name)) { dict.Add(c.name,c); } }; this.BGMList.ForEach(bgm => addClipDict(this.bgmDict,bgm)); this.SEList.ForEach(se => addClipDict(this.seDict,se)); } public void PlaySE(string seName) { if(!this.seDict.ContainsKey(seName)) throw new ArgumentException(seName + " not found","seName"); AudioSource source = this.seSources.FirstOrDefault(s => !s.isPlaying); if(source == null) { if(this.seSources.Count >= this.MaxSE) { Debug.Log("SE AudioSource is full"); return; } source = this.gameObject.AddComponent<AudioSource>(); this.seSources.Add(source); } source.clip = this.seDict[seName]; source.Play(); } public void StopSE() { this.seSources.ForEach(s => s.Stop()); } public void PlayBGM(string bgmName) { if(!this.bgmDict.ContainsKey(bgmName)) throw new ArgumentException(bgmName + " not found","bgmName"); if(this.bgmSource.clip == this.bgmDict[bgmName]) return; this.bgmSource.Stop(); this.bgmSource.clip = this.bgmDict[bgmName]; this.bgmSource.Play(); } public void StopBGM() { this.bgmSource.Stop(); this.bgmSource.clip = null; } }
ポイント
・実行にはSingletonMonoBehaviourクラスが必要です。→こちら・複数Scene跨いでも使えます。
・Scene内にAudioListenerが無い場合は生成します。
・AudioSourceを動的に生成します。
まとめ
やりたいと思ったことは実現できました。でもListとかDictionaryとかLinqをガンガン使ってるので
ゲーム開発って視点で見ると無駄の多いソースなのかも。
アプリ開発始めたころは省メモリ意識してたんだけど
結構動いてくれるから気にしないで書いちゃうのよね。
ソース載っけてみたので
”もっとこうした方がいいよ。" とか "自分はこんな風にしてるよ。”
っていうのがある方は是非おしえてください!
人のソース読みたい…。
それじゃまた!
→Unity系記事まとめ