2013年11月23日土曜日

【Unity】AudioManagerクラスを作ろう

さて、前の記事でシングルトンを提供するクラスができたので
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系記事まとめ

スポンサーリンク

Related Posts Plugin for WordPress, Blogger...