i-school - 3Dレールガンシューティング 発展15
 引き続き、音楽の面でのゲームの演出を追加していきます。



発展15 ーBGMの再生と切替機能ー

 この手順では場面に応じて自動的に再生する BGM を切り替える処理を実装していきます。

 4.SoundManager ゲームオブジェクトと、SoundManager スクリプトを作成する
 5.GameManager スクリプトと Title スクリプトを修正して、SoundManager スクリプトを使って、場面に合わせてBGMを自動的に切り替える制御処理を実装する



 新しい学習内容は、以下の通りです。

 ・AudioSource.Playメソッド、AudioSource.Stopメソッド
 ・DOTweenの補間機能の実装例 ーAudioSource.DOFadeメソッドを利用したBGMのクロスフェード演出処理ー
 ・AddComponent メソッド



4.SoundManager ゲームオブジェクトと、SoundManager スクリプトを作成する

1.設計


 BGM を再生する処理を考えた場合、BGM 用のゲームオブジェクトを作成し、そこにオーディオファイルを再生するための AudioSource コンポーネントをアタッチする方法が考えられます。
この場合、BGM を切り替える処理を行うために、新しくスクリプトを用意する必要があります。
BGM が2種類であればよいのですが、ゲームでは数種類を切り替えることが想定されますので、個別に設定したり、個別のスクリプトを用意することは
管理の面からも、実装のための準備の面からも難しい設計になります。

 そこで今回は、オーディオ関連の処理をすべて管理するためのマネージャークラスとして SoundManager スクリプトを作成して、BGM、SE、ボイスなどをまとめて管理するように設計を考えます。
ここの中に、先ほどの手順でインポートしたオーディオファイルをBGMとして再生したり、停止したりする制御の実装を行います。

 再生中のBGMを切り替えるにはいくつか手法がありますが、今回は2つの AudioSource コンポーネントを用意します。AudioClip は空にしておいて、
場面に応じて、再生させる AudioClip の内容を切り替えていく方法を使います。

 イメージとしては オーディオの再生機器が AudioSource コンポーネント、実際に再生されるオーディオファイルが AudioClip になります。



 SoundManager スクリプトですが、BGM だけではなく、SE や ボイスなど、オーディオファイルに関連する機能をすべて管理する役割を持たせます。
そのためこれらのオーディオ関係の処理は、いつどのスクリプトでもよいように GameData スクリプトを作成した際と同じように、
シングルトンデザインパターンを採用して設計を行うことを考えます。

 BGM に限らず、SE などは特に、いずれのスクリプトからでも実行命令が発生する可能性があります。
そういった場合、各スクリプトごとに SoundManager スクリプトの変数を用意して代入処理を行うのでは、非常に労力がかかります。
恐らくすべてのスクリプトに追加をするようになってしまう可能性もあります。

 こういったケースの場合は、各スクリプトが変数を用意して利用できる状態にするのではなく、
SoundManager 側が、いずれのスクリプトから、いつでも利用しても問題ない状態にしておく設計の方が管理もアクセスも容易になります。

 一方からの処理を考えるのではなく、双方の処理を見直して、どのように設計を行っておいたほうが
先々の利便性や修正作業、管理が簡単かつ、わかりやすくなるのかを、念頭に置いて設計を行うようにしましょう。


2.SoundManager スクリプトを作成する


 シングルトンデザインパターンで、SoundManager を作成します。
変数やメソッドも多く、処理も複雑ですので、処理を記述して満足するのではなく、
どの処理がどのように動いているか、どの処理と処理がつながっているかをしっかりと副種して、処理を把握出来るようにしましょう。
処理の内容がわからないままだと、自分で修正作業が行えなくなってしまうためです。


SoundManager.cs


 スクリプトを作成したらセーブします。


3.<AudioSource.Playメソッド、AudioSource.Stopメソッド>


 AudioSource.Playメソッドを利用することで、AudioSource コンポーネントの AudioClip にアサインされているオーディオファイルをゲーム内で再生することが出来ます。

 また、AudioSource.Stopメソッドを利用することで、AudioSource コンポーネントの AudioClip にアサインされているオーディオファイルの再生を停止することが出来ます。

 どちらのメソッドも、AudioSource コンポーネントを変数に代入することで命令を出すことが出来ます。

    [SerializeField]
private AudioSource[] audioSources;

// 新しい指定されたBGMを再生
audioSources[index].Play();

// 再生を停止
audioSources[index].Stop();

参考サイト
Unity公式スクリプトリファレンス
AudioSource
https://docs.unity3d.com/ja/current/ScriptReferenc...
Unity公式スクリプトリファレンス
AudioSource.Play
https://docs.unity3d.com/ja/current/ScriptReferenc...
Unity公式スクリプトリファレンス
AudioSource.Stop
https://docs.unity3d.com/ja/current/ScriptReferenc...


4.<DOTweenの補間機能の実装例 ーAudioSource.DOFadeメソッドを利用したBGMのクロスフェード演出処理ー>


 DOTweenの機能である、AudioSource.DOFadeメソッドを利用すると、指定した時間をかけて徐々にボリューム(音量) を制御することが出来ます。
第1引数に 変化後の Volume の値(動かしたい値)、第2引数には、Volume の値が変化するまでの時間を指定します。
Volume の値は AudioSource の Volume プロパティ欄を操作し、最小値は 0、最大値は 1 で指定を行います。

徐々にボリュームを小さくする場合
    // 徐々にボリュームを下げる
    audioSources[1].DOFade(0, CROSS_FADE_TIME).SetEase(Ease.Linear);   //  CROSS_FADE_TIME 秒かけて、現在のボリュームを 0 (最小値)にする
徐々にボリュームを大きくする場合
    // 徐々にボリュームを上げる
    audioSource.DOFade(0.1f, 0.75f);       // 0.75 秒かけて、現在のボリュームを 0.1f にする

この機能を上手く活用することで、BGMが突然切り替わったり、あるいはBGMが切り替わるまでの無音の時間を作らない演出が可能になります。
今回の場合、新しく流すBGMのボリュームを徐々に大きくしていき、その間に前に流れていたBGMのボリュームが徐々に小さくなるという、BGMのクロスフェード演出を行っています。

 ボリュームは 1.0f まで設定可能ですが、最大値にしてしまうと、今後追加する SE の音を最大にしても聴こえなくなる恐れがありますので
ここでは小さめに設定して、バランスを取りながらスクリプトの値を調整してください。変数にしてインスペクターから設定できるようにしてもいいでしょう。

 なお、SetEase メソッドの Ease.Linear を利用すると、フェードする処理が一定速度になります。ボリュームを等速で増減したい場合には活用してください。


5.SoundManager ゲームオブジェクトを作成して、SoundManager スクリプトをアタッチし、設定を行う


 ヒエラルキーの空いている場所を選択して右クリックをしてメニューを開き、Create Empty を選択して空のゲームオブジェクトを1つ作成します。
名前を SoundManager に変更します。

 先ほど作成した SoundManager スクリプトをドラッグアンドドロップしてアタッチしてください。



 続けて SoundManager ゲームオブジェクトを選択して、インスペクターにて SoundManager スクリプトのアタッチを確認し、設定を行います。

 SoundDataSO 変数に、Datas フォルダにある SoundDataSO スクリプタブル・オブジェクトをドラッグアンドドロップしてアサインします。
他の部分はそのままで問題ありません。


SoundManager ゲームオブジェクト インスペクター画像



 以上で設定は完了です。


5.GameManager スクリプトと Title スクリプトを修正して、SoundManager スクリプトを使って、場面に合わせてBGMを自動的に切り替える制御処理を実装する

1.設計


 SoundManager クラスは、シングルトンデザインパターンによって作成されています。
そのため GameData クラスと同じように、いずれのスクリプトからでも自由に参照して、メソッドを実行することが可能です。
BGM や SE の再生のたびに、各スクリプト内に SoundManager スクリプトの変数を用意して取得をしていると、
例えば、エネミーが SE を再生したいとなった場合、生成されるたびに SoundManager スクリプトの参照を取得する必要が生まれます。

 こういった【複数のスクリプトから参照される用途があり、汎用的に利用される情報】については、
シングルトンデザインパターンを採用することにより、各スクリプト内に新しい変数を追加する必要もなくなり、
BGM や SE の再生処理についてもメソッドを実行する命令文を1行記述すれば済みます。



 BGM を再生する場面として、ゲームの開始時があります。
 現在、ゲームを開始した際の進行状態は GameManager スクリプトの Start メソッドを利用して初期設置の管理を行っていますので、
GameManager スクリプトから SoundManager スクリプトに用意したBGMを再生するメソッドを呼び出すように処理を追加して、メインとなる BGMの再生処理を実行します。

 今回はもう1つ BGM を用意してあります。これは BOSS とのバトル用の BGM になりますので、ボスの出現に合わせて再生する BGM を切り替えたいと思います。
ボスの出現時には警告の演出がありますので、この演出に合わせて、場面に応じたBGMの切り替え処理を実装します

 この処理はボスの演出などを追加した際に、実装する予定として覚えておいてください。
TODO を記述しておくといいでしょう。



 SoundManager クラスに記述したメソッドは、GameData クラスと同じように、【クラス名.クラスの代入されている変数名.実行したい変数名かメソッド名(引数の指定)】の書式で記述します。

<シングルトンクラスのメソッドの実行命令>
  SoundManager.instance.PlayBGM(SoundDataSO.BgmType.Main);

 引数に BgmType を指定することにより、指定した BgmType の設定されている BgmData が参照されて利用される設計になっています。


2.GameManager スクリプトを修正する


 ゲーム開始に合わせて BGM を再生するようにしましょう。
どの部分に記述するかを考えて実装を行ってください。


GameManager.cs

<= クリックすると開きます。


 スクリプトを修正したらセーブします。


3.ゲームを実行して動作を確認する


 ゲームを実行してみましょう。ゲームの開始に合わせて、指定した BGM が再生されれば制御成功です。

 続いて、BGM を切り替える処理を実装します。


4.<応用> Title スクリプトを修正する


 タイトルシーンからゲームを開始した場合、どの部分に処理を書いておけば、BGM の再生処理が出来るようになるでしょうか。
Title スクリプトを修正して、実際に処理を考えて書き加えてみてください。

 そのためにはまず、BGM 用のデータを新しく追加する必要もあります
音源の用意が出来たら、音源のデータベースである SoundDataSO スクリプタブル・オブジェクトに新しい BGM 用のデータを追加します

 そして最後に BGM を流す処理を実装して完成です。
BGM を流す処理は、タイトルシーンの開始時に1回だけ実行するようにすれば制御できます
どういう処理があればいいのか、よく考えて実装に挑戦してください。
想定している処理を実行するためのメソッドが見当たらない場合には、自分でメソッドを付け加えてください。

 処理を考えるコツは、事前にどのような準備が必要で、それを利用してどのような制御を追加していけばいいのか、
処理の流れの全体像をイメージしていくことが大切です。

 設計が終了してから、処理を書いていくようにしてください。



 BGM を再生するメソッドを実行すると、前に流れていた BGM から、新しく指定した BGM へと自動的に切り替わるように制御を設計してあります
そのため、BGM を始めて再生する場合も、BGM を切り替える場合も、どちらも PlayBGM メソッドを実行すれば実装出来ます
引数に BgmType を指定しているのは、この切り替えにも対応するためです。


Title.cs

<= クリックすると開きます


 スクリプトを修正したらセーブします。


5.<AddComponent メソッド>


 SoundManager スクリプト内に新しく実装されているメソッドです。

 AddComponent メソッドは、ゲーム実行中において、対象のゲームオブジェクトに指定したコンポーネントを新しくアタッチするメソッドです。
インスペクターの一番下にある Add Component ボタンの処理を行うメソッドであるとも言えます。

        // BGM用 AudioSource追加
        BGM_Sources[0] = gameObject.AddComponent<AudioSource>();
        BGM_Sources[1] = gameObject.AddComponent<AudioSource>();

 今回は SoundManager スクリプトの Awake メソッド内に実装され、ゲームの実行時に、複数の AudioSource コンポーネントをアタッチする処理を行っています。
事前に AudioSource コンポーネントである場合には、インスペクターより1つずつコンポーネントをアタッチしておく必要がありますが、
SoundManager スクリプトの処理では、AudioSource コンポーネントの AudioClip プロパティの情報をスクリプト内で動的に変更しているため、
1つの AudioSource コンポーネントにつき、特定の AudioClip を指定するという設計ではありません。
そのため、事前にインスペクターに AudioSource コンポーネントが不要であるため、ゲームの実行に合わせてアタッチしています。

 なお今回は左辺に変数を用意して、その変数に対して AddComponent メソッドを実行しています。
AddComponent メソッドには戻り値があり、アタッチしたコンポーネントの情報を戻すことができますので、
このような処理を実装すると、AddComponent メソッドによってアタッチされたコンポーネントの情報を、左辺の変数に戻すことができるため、
実質的に GetComponent メソッドの処理も一緒に行える挙動となっています。

 戻り値を活用できるようになると非常に多くの処理を記述できるだけではなく、短縮した処理も実装可能になります。

Unity公式スクリプトリファレンス
AddComponent
https://docs.unity3d.com/ja/current/ScriptReferenc...


6.ゲームを実行して動作を確認する


 タイトルシーンからゲームを実行し、BGM が流れることを確認してください。
その上で、メインシーンへ遷移し、その際に、BGM が自動的に切り替われば制御成功です。



 この BGM を切り替える方法を覚えておいてください。
他に利用する場面としては、ボスが出現するタイミングや、ステージをクリアした際にで BGM を切り替えることを想定します。



 以上でこの手順は終了です。

 => 次は 発展16 ーSEの再生ー です。