ゲームを作るに当たって、最後に手を入れがちですが、とても重要なのが「サウンド」です。
Unityには標準のサウンド機能(AudioClip,AudioSource,AudioListener)があるのですが、これをそのまま使うのはちょっと大変です。そのため、サウンドマネージャー(SoundManager)を作成し、使用することが多いです。
今回はそのサウンドマネージャーの作り方について解説していきたいと思います。
プロジェクトの作成
ではやってみましょう。 Unityで空の2Dプロジェクトを作成し、(プロジェクト名は何でも良いですが、ここでは「SoundManagerLesson」としました)
Unityエディタが起動しましたら、Assetsフォルダに「Sounds」フォルダを作っておきます。
では、まず音素材をインポートします。
音素材インポートしてAudio ClipとしてUnityに登録
音素材はすでにお持ちの方は好きな音素材を4ファイルほどインポートしていただければいいですが、講座上は 効果音ラボ様の、ボタン・システム音[1] から、
- 決定、ボタン押下1.mp3
- 決定、ボタン押下2.mp3
- 決定、ボタン押下3.mp3
- 決定、ボタン押下4.mp3
をダウンロードしてきて使います。
初学者の方は揃えたほうがわかりやすいと思いますので同じく上記ファイル4つをダウンロードしておいてください。(以降、この4ファイル名を想定した内容になりますので、ご自分で用意した音素材を利用するかたは、適宜読み替えてください。)
では、音素材は先程作った Assets/Sounds フォルダにドラッグアンドドロップしてインポートします。
この1ファイル1ファイルが「AudioClip」です。これが「音源データ」、ちょっと古いですが「音楽CD」だと置き換えるとわかりやすいです。
Audio Source、Audio Clip、AudioListenerの役割の違い 実際に音を鳴らしてみる
では、そのうちの一つ、「決定、ボタン押下1」をSceneビューに直接ドラッグアンドドロップしてみましょう。
自動的に作成されるGameObject(決定、ボタン押下1)を選択して、Inspectorで確認をするとAudio Source コンポーネントがついてることがわかります。
この、「Audio Source」は言わば「CDプレイヤー兼スピーカー」です。
では、Play On Awake(起動したら再生)にチェックが入っていることを確認して再生ボタンを押してみましょう。
どうでしょうか。 音が鳴りましたね。
「音が聞こえる」 ということは、「耳」があるということです。
UnityのSceneには最初から「耳」の役割をする「AudioListener」がMain Camera に準備されています。
まとめるとこうなります
AudioClip | 音源、音楽CD |
AudioSource | CDプレイヤー、スピーカー |
AudioListener | 耳 |
さて、音は鳴りましたがゲームの音はシーンが始まってすぐ鳴らしたいものばかりじゃないですよね。
では、「決定、ボタン押下1オブジェクト」をサウンドテスト用オブジェクトに修正して、マウスクリックで音が再生されるようにしましょう。
サウンドテスト用オブジェクトの作成 Playメソッドでスクリプトから音を鳴らす
まず、この自動的に作られたオブジェクト名では勝手が悪いので名前を変更します。
Hierarchyで「決定、ボタン押下1オブジェクト」 を選択し、名前を「SoundTest」に修正します。
次に、AddComponentからNew Script で 「SoundTest」スクリプトを追加します。
スクリプトは以下のように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundTest : MonoBehaviour { [SerializeField] private AudioSource source; //スピーカー・CDプレイヤー [SerializeField] private AudioClip clip1; //音源データ1 [SerializeField] private AudioClip clip2; //音源データ2 void Update() { if (Input.GetMouseButtonDown(0)) //左クリック { source.clip = clip1; //再生したいclipを指定して source.Play(); //再生 } if (Input.GetMouseButtonDown(1)) //右クリック { source.clip = clip2; //再生したいclipを指定して source.Play(); //再生 } } } |
左クリックでInspectorで指定したclip1が、右クリックでclip2が再生されるようになっています。
スクリプトから音を任意のタイミングで再生したい場合、通常このようにAudioSourceとAudioClipを何らかの方法(上記スクリプトではSerializeFieldにして、Inspectorから)で指定しできるようにし、
実際に再生するときはAudioSource
のclip
に再生するAudioClip
を指定してから、Playメソッドを呼んでいます。(※PlayOneShotというメソッドを使う方法もあります)
では、スクリプトを忘れずに保存して、UnityEditor上のInspectorで、AudioSource、AudioClipを指定しましょう。
Source(AudioSource)には、自分自身についている AudioSourceを、Clip1、2にはそれぞれAssets/Sounds から 「決定、ボタン押下1」と「決定、ボタン押下2」を設定しておきます。
また、このままだと実行と同時にAudioSourceに最初からセットされている音が再生されてしまうので、Play On Awake のチェックは外しておきます。
では、実行して確認してみましょう。
左クリックと右クリックでそれぞれ指定した音が再生されると思います。
ここで色々試すとわかるのですが
①右クリックと左クリックを同時にクリックしてもなるのはどちらかの音
②効果音が鳴っている間にクリックをすると、前の効果音は中断されて、新しい音が再生される
という状態です。
サウンドマネージャーを作る
さて、単純に音を鳴らすだけなら比較的すぐ出来ましたが、ゲームで音を鳴らしたいケースはたくさんありますよね。
- ジャンプボタンを押したらジャンプするので、そのときにはジャンプ音を鳴らしたい
- コインを取ったら、コインを取得した音を鳴らしたい
- ボタンを押したら、クリック音を鳴らしたい
- ゴールしたら、ファンファーレを鳴らしたい
- 敵のHPが0になったら、爆発音を鳴らしたい
大体は、「プレイヤーが起こした行動」に対して「効果音」がなります。
そのため、基本的にはスクリプトで複数のAudioSourceとAudioClipを管理して音を鳴らす必要があります。
しかし例えば
- コインを取ったら、コインを取得した音を鳴らしたい
を例に上げると、コインが画面上に100個あったとして、全て(100個)のコインオブジェクト一つ一つにAudioSourceコンポーネントが必要でしょうか?
コインを連続して取得した場合には音階が上がっていく演出なんかもいいですよね!
でも、全てのコインに音階の違うAudioClipを持たせて置くことに?
やってみるとわかるのですが、この方法はとても手間がかかります(もちろん、その方法が正解のパターンもあります。 音の出どころが重要な3Dゲームなどでは特に)
なので、
AudioClip(音源)とAudioSource(CDプレイヤー)を一括で管理するオブジェクト
が欲しくなります。 これが俗に言う「SoundManager(サウンドマネージャー)」です。
SoundManagerのような汎用的なオブジェクトは、要求する機能が人それぞれ(ゲームそれぞれ)なので、100人いれば100の細かく機能が異なるSoundManagerが出来たりします。
もちろん本講座で作成したSoundManagerをそのまま使っても良いですが、適宜カスタマイズするのも勉強になると思います。
サウンドマネージャーに必要な3機能 音の管理・音の名称設定・音割れ防止
今回作るSoundManagerに必要な要件としては
- 手軽に効果音が管理・再生できる
- 再生する効果音の指定にわかりやすい別名がつけられる
- 同じ音源が同一・または近辺フレームで鳴って音割れするのを避ける
とします。
- 手軽に効果音が管理・再生できる
はそのままですが、
- 再生する効果音の指定にわかりやすい別名がつけられる
は、ちょっとめずらしいかもしれません。
先程作ったSoundTestスクリプトを例に上げると
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundTest : MonoBehaviour { [SerializeField] private AudioSource source; //スピーカー・CDプレイヤー [SerializeField] private AudioClip clip1; //音源データ1 [SerializeField] private AudioClip clip2; //音源データ2 void Update() { if (Input.GetMouseButtonDown(0)) //左クリック { source.clip = clip1; //再生したいclipを指定して source.Play(); //再生 } if (Input.GetMouseButtonDown(1)) //右クリック { source.clip = clip2; //再生したいclipを指定して source.Play(); //再生 } } } |
再生するものが決まっている場合などはこれでもいいんですが、効果音候補がたくさんある、または逆に「ここで音を鳴らす」と決めてはいるけれど、まだ効果音を探していない。
等、具体的に「どの音源を再生する」とは決められない時などに
1 2 |
soundManager.Play("右クリック"); soundManager.Play("左クリック"); |
このように、文字列の別名で再生する効果音を指定しておいて、後でこの「右クリック」や「左クリック」の文字列に対してペアのAudioClipを指定する。という機能です。(詳しくは後述)
また
- 同じ音源が同一・または近辺フレームで鳴って音割れするのを避ける
は、何も考えずにAudioSourceとAudioClipで効果音をつけているとありがちなのですが、だいぶ前に前述した例の
- コインを取ったら、コインを取得した音を鳴らしたい
のような、1つとは限らないアイテムの取得音で、画面上に大量にあった場合にそのまま愚直に効果音を再生すると、同じ音が一気に再生されることになります。
するとどうなるかというと、良くて「音量が急に大きく」なってしまいますし、悪くて「音割れ」して、ガビガビしたノイズが出てしまい、ゲームをプレイしてくれている人に不快感を与えてしまいかねません。
この辺りも考慮したサウンドマネージャーを作っていきたいと思います。
SoundManagerオブジェクト作成
では、早速作っていきましょう。
SceneビューでCTRL+SHIFT+Nキーを押して新規オブジェクトを作成し、名前は「SoundManager」にしておきます。
次に、AddComponentからNew Script で 「SoundManager」スクリプトを追加します。
では、このSoundManagerスクリプトを修正していきます。
まず、
- 手軽に効果音が管理・再生できる
を作っていきましょう。
AudioClip(音源)を再生するためのAudioSourceを準備します。
AudioSourceはCDプレイヤー兼スピーカーでしたね。
基本、1つのAudioSourceでは1つのAudioClipしか再生出来ません。逆にいうとAudioSourceの数だけ、(理論上)効果音が同時に鳴らせることになります。
そのため、最初にある程度の数用意&管理しておきたいので
1 2 3 4 5 6 7 8 9 10 11 |
//AudioSource(スピーカー)を同時に鳴らしたい音の数だけ用意 private AudioSource[] audioSourceList = new AudioSource[20]; private void Awake() { //auidioSourceList配列の数だけAudioSourceを自分自身に生成して配列に格納 for (var i = 0; i < audioSourceList.Length; ++i) { audioSourceList[i] = gameObject.AddComponent<AudioSource>(); } } |
このように、SoundManagerオブジェクトにAddComponent(コンポーネントの追加)でAudioSourceを指定数(今回は20個)追加して、配列で管理するようにしておきます。
次に、このAudioSourceは1回使ったら終わりではなく、使いまわす必要があります。
しかし、音は再生時間が短いものもあれば長いものもありますよね。
10秒の効果音を再生している時に、別の音を鳴らすからといって10秒の効果音再生中のAudioSourceを使ってしまえば、当然効果音が途中で切れてしまいます。
そこで「未使用(使用済み)のAudioSource」を取得するメソッド「GetUnusedAudioSource」メソッドを用意しましょう。
1 2 3 4 5 6 7 8 9 10 |
//未使用のAudioSourceの取得 全て使用中の場合はnullを返却 private AudioSource GetUnusedAudioSource() { for (var i = 0; i < audioSourceList.Length; ++i) { if (audioSourceList[i].isPlaying == false) return audioSourceList[i]; } return null; //未使用のAudioSourceは見つかりませんでした } |
AudioSourceにはisPlaying
というプロパティがあり、それを見ることで現在再生中かどうかの判断が出来ます。
これを使用し、isPlaying == false
、すなわち未使用(または使用済み)のAudioSourceを見つけてreturn
で返却しているわけです。
なお(レアケースですが)全ての用意したAudioSource(今回は20個)が全て使用中。という場合はnullを返却するようにしてあります。
Linq
なお、このGetUnusedAudioSourceメソッドですが、Linq(Language-Integrated Query)という書き方(+ expression bodied)で書くと、なんと以下の1行になります。
1 |
private AudioSource GetUnusedAudioSource() => audioSourceList.FirstOrDefault(t => t.isPlaying == false); |
※ただし、使用するためには using に System.Linq; の追加が必要になります
Linqは配列やListなどの操作をする拡張メソッドが多数用意されており、使いこなせると非常に便利ですので、どこかの機会で勉強してみるのも良いと思います。
最後に、引数で渡された音源(AudioClip)を未使用のAudioSourceを使用して再生する、Playメソッドを作ります。
1 2 3 4 5 6 7 8 |
//指定されたAudioClipを未使用のAudioSourceで再生 public void Play(AudioClip clip) { var audioSource = GetUnusedAudioSource(); if (audioSource == null) return; //再生できませんでした audioSource.clip = clip; audioSource.Play(); } |
もし、未使用のAudioSourceをローカル変数audioSource
に代入し、未使用のAudioSourceが見つからない場合(nullだった場合)は何もせずにreturn
をするようにしています。
これで、
- 手軽に効果音が管理・再生できる
を満たしたSoundManager プロトタイプVer1 の完成です。
現時点でのSoundManagerスクリプトは以下の通りです(最初から用意されているStartメソッド、Updateメソッドは使用しないので削ってあります)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundManager : MonoBehaviour { //AudioSource(スピーカー)を同時に鳴らしたい音の数だけ用意 private AudioSource[] audioSourceList = new AudioSource[20]; private void Awake() { //auidioSourceList配列の数だけAudioSourceを自分自身に生成して配列に格納 for (var i = 0; i < audioSourceList.Length; ++i) { audioSourceList[i] = gameObject.AddComponent<AudioSource>(); } } //未使用のAudioSourceの取得 全て使用中の場合はnullを返却 private AudioSource GetUnusedAudioSource() { for (var i = 0; i < audioSourceList.Length; ++i) { if (audioSourceList[i].isPlaying == false) return audioSourceList[i]; } return null; //未使用のAudioSourceは見つかりませんでした } //指定されたAudioClipを未使用のAudioSourceで再生 public void Play(AudioClip clip) { var audioSource = GetUnusedAudioSource(); if (audioSource == null) return; //再生できませんでした audioSource.clip = clip; audioSource.Play(); } } |
では早速使ってみましょう。
先ほどのSoundTestスクリプトを修正し、SoundManagerを使って効果音が再生できるようにしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundTest : MonoBehaviour { [SerializeField] private SoundManager soundManager; //サウンドマネージャー [SerializeField] private AudioClip clip1; //音源データ1 [SerializeField] private AudioClip clip2; //音源データ2 void Update() { if (Input.GetMouseButtonDown(0)) //左クリック { soundManager.Play(clip1); //サウンドマネージャーを使用して効果音再生 } if (Input.GetMouseButtonDown(1)) //右クリック { soundManager.Play(clip2); //サウンドマネージャーを使用して効果音再生 } } } |
もう自分自身のAudioSourceは使う必要がないので(SoundManagerが管理してくれるものを使うので)、AudioSourceのメンバ変数は削除し、代わりにSoundManagerをInspectorから指定出来るようにしています。
また、効果音の再生もSoundManagerのPlayメソッドにAudioClipを指定して再生するように修正しました。
では2つのスクリプト(SoundManager,SoundTest)を忘れずに保存し、UnityEditorに戻りましょう。
SoundTestのInspectorでSoundManagerがセット出来るようになっていますので、HierarchyのSoundManagerオブジェクトをドラッグアンドドロップでセットしておきます。
また、自身のAudioSourceはもう使用しませんので、右クリック→Remove Componentで削除してしまいましょう。
では、再生ボタンを押して確認してみましょう。
AudioSourceの管理をSoundManagerに任せているので、先程の修正前のSoundTestスクリプトの
①右クリックと左クリックを同時にクリックしてもなるのはどちらかの音
②効果音が鳴っている間にクリックをすると、前の効果音は中断されて、新しい音が再生される
という状態が解消され、マウスボタンを連打をしたり、右クリックと左クリックを同時にしたりすると音が多重に重なって再生されているのが分かると思います。
別名文字列による効果音再生
では次に
- 再生する効果音の指定にわかりやすい別名がつけられる
の為に、文字列(string
)→nameと、実際の音源(AudioClip
)→audioClipのペアを管理するクラス、SoundDataを作り、そのSoundDataを配列(SoundData[]
)で管理するsoundDatasもメンバ変数で用意します。
なお、このSoundDataクラスはSoundManagerのインナークラスとして作るので、追加場所はSoundManagerクラスの中になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundManager : MonoBehaviour { [System.Serializable] public class SoundData { public string name; public AudioClip audioClip; } [SerializeField] private SoundData[] soundDatas; |
まだ別名用の枠を用意しただけですが、スクリプトを保存し、UnityEditorに戻って確認をしてみましょう。
SoundManagerスクリプトのInspectorにSound Datas という項目が増え、Sizeを指定すると(今回は4にしました)別名(Name)と音源(Audio Clip)がペアでセット出来るようになりましたね!
右クリック | 決定、ボタン押下1 |
左クリック | 決定、ボタン押下2 |
Zキー | 決定、ボタン押下3 |
Xキー | 決定、ボタン押下4 |
例では上記のようにセットしましたが、適当に入れ替えても構いません。
(というより、後でここを入れ替えるだけで再生される効果音を切り替えられるようにするのが最終目的です)
では、実際にこの「別名」を指定することで「別名」とペアになっている音源(AudioClip)を再生されるように管理していきましょう。
この、SoundData配列変数 soundDatas
から毎回name(名前)をキーにして探しても良いのですが、仮に100個のSoundDataがsoundDatas
に格納されたと考えると、目的の別名を探すのに最速で1個め、最遅で100個目なので、平均で50個探すことになります。登録件数が多ければ多いほど探索に時間がかかるようになってしまいますね(O(n)というやつです。)
そのため、nameをキーとしてSoundDataを管理するDictionary→(Dictionary<string,SoundData>
)である、soundDictionaryを先にメンバ変数に用意し
1 2 |
//別名(name)をキーとした管理用Dictionary private Dictionary<string, SoundData> soundDictionary = new Dictionary<string, SoundData>(); |
AwakeメソッドでsoundDatas
を全てAddするようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
private void Awake() { //auidioSourceList配列の数だけAudioSourceを自分自身に生成して配列に格納 for (var i = 0; i < audioSourceList.Length; ++i) { audioSourceList[i] = gameObject.AddComponent<AudioSource>(); } //soundDictionaryにセット foreach (var soundData in soundDatas) { soundDictionary.Add(soundData.name, soundData); } } |
では、別名指定による効果音再生処理としてPlayメソッドを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 |
//指定された別名で登録されたAudioClipを再生 public void Play(string name) { if (soundDictionary.TryGetValue(name, out var soundData)) //管理用Dictionary から、別名で探索 { Play(soundData.audioClip); //見つかったら、再生 } else { Debug.LogWarning($"その別名は登録されていません:{name}"); } } |
まず、DictionaryのTryGetValueというメソッドを使っています。
これは、Dictonary内に第1引数で指定したキー(今回はstring:name)が見つかれば、第2引数で指定したout変数に格納してtrueを返却、見つからない場合はfalseを返却するというものです。
無事見つかった場合(trueの場合)は、既にあるAudioClipを受け取るPlayメソッドを呼んで再生、
見つからなかった場合(falseの場合)はログに警告を表示しています。
メソッドのオーバーロード(Overload):多重定義
「え!? Playメソッドって既にあるのに、またPlayメソッドを追加するの!?」と思った方もおられるかもしれませんね。
もちろん、これはタイピングミスでも、そしてエラーにもなりません。正しい処理です。
C#では引数で区別さえできればメソッド名が重複しても構わないからです(C#に限らず他の言語でもありますが)
これをオーバーロード:多重定義と呼びます。
もちろんメソッド名を分けても良いといえば良いのですが(PlayClipとPlayWithNameなど)、処理の意味合いが全く同じ(今回の場合、どちらも効果音の「再生」)の場合、逆にメソッド名は同じにしてしまって、引数として渡すものによって処理が分岐されるほうが使う側からすると理解しやすいのでこのオーバーロードを使いました(今回は正直微妙なラインですが・・・)
用法用量を守って正しくお使いください。
これで
- 再生する効果音の指定にわかりやすい別名がつけられる
を満たしたSoundManager プロトタイプVer2 が完成しました。
SoundManagerスクリプト全体は以下になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundManager : MonoBehaviour { [System.Serializable] public class SoundData { public string name; public AudioClip audioClip; } [SerializeField] private SoundData[] soundDatas; //AudioSource(スピーカー)を同時に鳴らしたい音の数だけ用意 private AudioSource[] audioSourceList = new AudioSource[20]; //別名(name)をキーとした管理用Dictionary private Dictionary<string, SoundData> soundDictionary = new Dictionary<string, SoundData>(); private void Awake() { //auidioSourceList配列の数だけAudioSourceを自分自身に生成して配列に格納 for (var i = 0; i < audioSourceList.Length; ++i) { audioSourceList[i] = gameObject.AddComponent<AudioSource>(); } //soundDictionaryにセット foreach (var soundData in soundDatas) { soundDictionary.Add(soundData.name, soundData); } } //未使用のAudioSourceの取得 全て使用中の場合はnullを返却 private AudioSource GetUnusedAudioSource() { for (var i = 0; i < audioSourceList.Length; ++i) { if (audioSourceList[i].isPlaying == false) return audioSourceList[i]; } return null; //未使用のAudioSourceは見つかりませんでした } //指定されたAudioClipを未使用のAudioSourceで再生 public void Play(AudioClip clip) { var audioSource = GetUnusedAudioSource(); if (audioSource == null) return; //再生できませんでした audioSource.clip = clip; audioSource.Play(); } //指定された別名で登録されたAudioClipを再生 public void Play(string name) { if (soundDictionary.TryGetValue(name, out var soundData)) //管理用Dictionary から、別名で探索 { Play(soundData.audioClip); //見つかったら、再生 } else { Debug.LogWarning($"その別名は登録されていません:{name}"); } } } |
では、先ほどのSoundTestスクリプトをさらに修正し、別名を指定して効果音が再生できるようにしてみましょう。
今、SoundTestスクリプトは以下の状態のはずです
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundTest : MonoBehaviour { [SerializeField] private SoundManager soundManager; //サウンドマネージャー [SerializeField] private AudioClip clip1; //音源データ1 [SerializeField] private AudioClip clip2; //音源データ2 void Update() { if (Input.GetMouseButtonDown(0)) //左クリック { soundManager.Play(clip1); //サウンドマネージャーを使用して効果音再生 } if (Input.GetMouseButtonDown(1)) //右クリック { soundManager.Play(clip2); //サウンドマネージャーを使用して効果音再生 } } } |
AudioClipは直接持つ必要がなくなったので、10~14行目のメンバ変数 clip1とclip2は削除します。
そして、soundManagerのPlayメソッドでAudioClipを指定していましたが、別名を指定するように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundTest : MonoBehaviour { [SerializeField] private SoundManager soundManager; //サウンドマネージャー void Update() { if (Input.GetMouseButtonDown(0)) //左クリック { soundManager.Play("←クリック"); //サウンドマネージャーを使用して効果音再生 } if (Input.GetMouseButtonDown(1)) //右クリック { soundManager.Play("右クリック"); //サウンドマネージャーを使用して効果音再生 } } } |
“Xキー”,”Zキー”という別名でもAudioClipを登録してあるので、そちらも確認できるようにコードを追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundTest : MonoBehaviour { [SerializeField] private SoundManager soundManager; //サウンドマネージャー void Update() { if (Input.GetMouseButtonDown(0)) //左クリック { soundManager.Play("左クリック"); //サウンドマネージャーを使用して効果音再生 } if (Input.GetMouseButtonDown(1)) //右クリック { soundManager.Play("右クリック"); //サウンドマネージャーを使用して効果音再生 } if (Input.GetKeyDown(KeyCode.X)) //Xキー { soundManager.Play("Xキー"); } if (Input.GetKeyDown(KeyCode.Z)) //Zキー { soundManager.Play("Zキー"); } } } |
ではスクリプトを保存して右クリック、左クリック、Xキー、Zキーでそれぞれ効果音が再生されるか確認してみましょう。
どうでしょうか。SoundManagerで管理された別名と音源のペアで効果音が再生出来るようになりましたね!
Cキーも追加したくなった
さて、ゲームを作っていると、予定より機能を追加することになるなんてことは日常茶飯事です。
Cキーも追加されることになったとします。しかし、効果音は4つ全て使ってあります。今やっている実装が終わったら、新しい効果音を探してきて、それからスクリプトを修正して・・・
となんやかんややっていて効果音を付け忘れ、Cキーだけ音が鳴らない。
なんてことは回避したいですよね。
そういう時におすすめしているのが、効果音再生の処理を先に書いてしまう事です。
このようにSoundTestスクリプトに、Cキーが押された場合の処理を追加してしまいます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundTest : MonoBehaviour { [SerializeField] private SoundManager soundManager; //サウンドマネージャー void Update() { if (Input.GetMouseButtonDown(0)) //左クリック { soundManager.Play("左クリック"); //サウンドマネージャーを使用して効果音再生 } if (Input.GetMouseButtonDown(1)) //右クリック { soundManager.Play("右クリック"); //サウンドマネージャーを使用して効果音再生 } if (Input.GetKeyDown(KeyCode.X)) //Xキー { soundManager.Play("Xキー"); } if (Input.GetKeyDown(KeyCode.Z)) //Zキー { soundManager.Play("Zキー"); } if (Input.GetKeyDown(KeyCode.C)) //Cキー { soundManager.Play("Cキー"); } } } |
これでスクリプト保存をして、UnityEditorで実行してみましょう。
Cキーを押すと
登録されていない旨の警告(Warning)は出ますが、ゲームが中断したりはしませんから、他部分も作り込んでいくことが出来ます。
このように、警告が表示される状態にまずしておけば効果音付け忘れもなくなりますよね。
もちろん、警告を警告のまま放っておいては意味がありませんから、折を見てちゃんと効果音を探してSoundManagerに追加しましょう。
なお、同じ音源(AudioClip)を複数の別名につけても構いません。
一旦、適当な音を付けておいて、最後に正しくしていく。 という方法も取れますね。
次回
今回は
- 手軽に効果音が管理・再生できる
- 再生する効果音の指定にわかりやすい別名がつけられる
まで作りました。
次回は
- 同じ音源が同一・または近辺フレームで鳴って音割れするのを避ける
を実装して完成を目指したいと思います。
次回の記事:
コメント