GP12

効果音をスクリプトで制御してゲームを演出する好例


コマンド入力待ちでBGMの小節がループを始める、

アクション(ボタン選択)のタイミングで次の小節に進み、

アクション成功でBGMが音楽的にも解決するので気持ちがいい。

以下にRoll a Ballや自作ゲームの改造例を示す。

この時間はRoll a Ballの改造の他の自作ゲームやSnap!のゲームの制作時間にしてもよい。

以下の作業を行う実験用のシーンを既存のシーンから適当に選んでコピーして準備する

ボールをジャンプさせる

ゲームステージに大幅な修正が必要になる場合がある。
元のPlayerControllerスクリプトをバックアップして元に戻せるようにしておくとよい。

参考記事: https://gametukurikata.com/letstrymakeit/makeasimpleactiongame/simpleaction22

 ステップ1 無限にジャンプ可能
InputSysmte Actionの設定
ジャンプ力の設定とAddForceのImpulseモード
 ステップ2 一定時間に一回ジャンプ可能
 ステップ3 着地状態ならジャンプ可能
 ステップ4 プレイヤー追跡カメラの調整(Y軸移動無し)
 ステップ5 プレイヤー追跡カメラの調整(ステップ型Y軸移動)


ステップ1 無限にジャンプ可能

EXのサブページの キー入力の割り当て変更を参照してジャンプ用のアクション(空白キーと右クリック)を設定

または

ProjectのInputフォルダに保存(Roll a Ballチュートリアル)の

RollaBall(Input Action Asset)

をダブルクリックで開く

Action Maps  の Player を選択

Actions の + ボタンを押す

Jump」と入力

<No Binding> を選択

Path の横の▼ボタンを押す

 Listenボタンを押す

キーボードの「スペースキー」を押す

Listening for Buttonのリストに表示されたものから

Space [Keyboard]

をクリックする

SpaceキーによるJump操作をキーボード&マウス用に割り当てる

 Use in control scheme を Keyboard&Mouse に設定

マウスの右ボタンでJumpする機能を追加する。

Jump アクションの + ボタンを押して

Add Binding

を選択する。

スペースキーの場合と同様に設定する。

Action設定パネルを閉じてファイルを保存する。


PrefabsのPlayerの設定を確認する。

Player InputコンポーネントのBehaviorが Send Messages になっている。
メッセージに OnJump ※が追加されている。
※アクションの設定で追加したアクション「Jump」の前に「On」が付いたものになる。
公式資料参照

OnJumpメッセージを受け取るメソッドを追加する。

PlayerController.cs を編集する。

ジャンプ力の設定

OnJumpメソッドの追加

FixedUpdateメソッドの修正
AddForceのImpulseモードでJump時に力を加える

無限落下バグ

ジャンプしてステージ外へ落下すると無限に落下し続けてゲームを続けられなくなる。
落下不能なステージを作成するか、落下時の対応を考える。期末課題で工夫できるポイントである。

次のような条件でリスタート、ワープ、ゲームオーバー、ペナルティなどを導入する。

・Y座標を監視

・キルゾーンやワープゾーンを設置(Trigger状態の非表示オブジェクトで判定)

・接触でRestartする床を設置

床のすり抜けバグ

ジャンプするが高所からの落下で床に衝突して止まらずにすり抜けて落下することがある。

判定精度を上げて対策するか、すり抜けバグを利用したステージ構成にすることが考えられる。

衝突判定の精度について再確認(資料リンク)するとよい。

逆に、精度を落として床をすり抜けるようにしても面白い。

ステップ2 一定時間に一回ジャンプ可能

Jumpキーの入力にクールダウンタイムを設定する。
キー入力後に一定期間の入力無効状態を作る。

進捗管理 月曜5時間目クラスはここまで解説し、BGMの設定に進んだ

ステップ3 着地状態ならジャンプ可能

参照記事 Raycastを利用して接地判定を行う

Jump可能条件に接地状態(ボールの下に床などのオブジェクトが存在するか)の判定を追加する

CheckGroundedメソッドを追加する

(ステップX)ジャンプした際に効果音を再生する。

効果音をProjectに読み込む(FileをSoundsフォルダにDnD)
PlayerのPrefabにAudio SourceSourceを追加
Audio SourceにAudioClip(効果音のファイル)を追加
PlayerController.csを編集
Jump成功時に効果音を再生するコードを追加

ステップ4 プレイヤー追跡カメラの調整(Y軸移動無し)

CameraController.csを編集する。

カメラの初期Y座標を記録する camera_y を用意して、
Startメソッドで初期座標を記録、
LateUpdateでY座標以外にOffset座標を加える。

ステップ5 プレイヤー追跡カメラの調整(ステップ型Y軸移動)

Playerが一定距離以上Y軸方向に移動した場合にカメラを移動させるようにCameraControllerを修正する。

 PlayerがJumpや落下で小さくY軸方向に移動してもしてもカメラは上下に移動しない
 Playerがステージの上下の改装に移動するなど、大きくY軸方向に移動した場合にはCameraをY軸方向に追随させる

坂道を用意してPlayerがY軸の上下方向に移動できるようにしておく。

Hierarchyに3D Object -> Cude を追加
Scaleを変更して板状にする。
回転ツールで傾けて
移動ツールで移動

Playerの初期Y座標をplayer_y_origに記録する。


 関数の紹介
Mathf.Sign 値の符号を調べる。+1 -1 0のいずれかの値になる。
Math.Abs 値の絶対値を調べる。
Math.Floor 小数点を切り捨てる。マイナス値はより小さくなる方向に切り捨てる。

例) -1.5 → -2.0

ここではこれらの関数を使用して、小数点を0方向に丸める処理をしている。

例) 0.5→0 -1.5→ -1.0

(ステップY)カメラをスムーズに移動させる方法を調べて実装する。高機能なCameraControllerを探す。
ステップ5で作成したカメラは、Y軸移動の際にワープする。
画面が急に切り替わるのでPlayerは戸惑うことだろう。スムーズに切り替わるようなアニメーション処理を入れたいところ。
他にも、PlayerとMain Cameraの間に障害物が挟まるとCameraが障害物にめり込んでシーンの描画に不都合が生じる。
Playerの表示と障害物の表示について、実際のゲームではどのように処理されているか観察してみよう。

シーンのBGM

参照記事 https://xr-hub.com/archives/18550

【Unity】AudioMixerで遊んでみよう!(1/3) https://zenigane138.hateblo.jp/entry/2018/02/20/225510


(内容)
シーンで切り替わるBGM
ステージクリア時のフェードアウト
シャッフル再生されるBGM


Audio Mixerの設定:
Audio Mixerのパネル(Ctrl + 8)からBGMとSEの調整フェーダーを追加する。

NewAudioMixerを選択(名前を付けていなかった場合)

Groupsの+ボタンを押す

Masterの下の階層に BGM を作る

Masterを選択

Groupsの+ボタンを押す

Masterの下の階層に SE を作る


  Masterのフェーダーで全体の音量の調整して、BGMとSEを個別に調整する設定ができた。※AudioMixerのフェーダーはシーン再生中に操作できない。不便。

BGMの音源を用意する。


 例) 魔王魂 からFree BGMをダウンロード(ファイル形式MP3)


UnityのProjectのSoundsフォルダにDLしたファイルをDnDして登録する。


PlayerのPrefabに DLしたAudioClipをDnDする。Audio Sourceが追加され、AudioClipが設定される。

※BGMはプレイ中にいつも聞こえる必要がある。
※Unityでは3D音響に対応するためAudioSource(音源)とAudioListener(各音源をMixingして音声出力)を用いる。
※このシーンのAudioListenerは  Main Camera に設定されている。
※以下ではBGMの音源をAudioListenerの付近にあるPlayerにアタッチしてPlayerが移動しても常に聞こえるようにする。

PlayerのAudio Sourceを調整する

Loop を On

Output を BGM

進捗管理 月5のクラスは「AudioMixerのエフェクト設定」までスキップした

(ステップZ)Player以外にAudioClipをアタッチする。Unityの3Dサウンドの設定を行えば、AudioListenerを持つPlayerが接近したときに距離に応じて聞こえる音や、立体音響(主に左右のステレオ)を実現できる。

シーン毎に異なるBGM

 GameObjectのPlayer(Prefabでなく)のAudioSourceのAudioClipを各シーンごとに異なるものに入れ替えればよい。

ステージクリア時にBGMをフェードアウト

 参照記事 https://futabazemi.net/unity/volume_down/

PlayerController に BGMフェードアウトのスクリプトを組み込む。

修正点1: AudioSourceコンポーネントを取得するコードを追加

    private AudioSource audioSource;


    void Start()

    {

        audioSource = GetComponent<AudioSource>();


修正点2:ステージクリア時にBGMのフェードアウトを開始させる
このコードではコルーチンをメソッド名で呼び出している。
※C#のリフレクションによるメタプログラミングの例

            StartCoroutine("FadeOut");


修正点3:コルーチン用のメソッドを追加
ボリュームを0に向かって徐々に下げている。
※0.1秒のウェイトタイムが入っていることに注意

    private IEnumerator FadeOut()

    {

        while (audioSource.volume > 0)

        {

            audioSource.volume -= 0.01f;

            yield return new WaitForSeconds(0.1f);

        }

    }

複数のBGMを設定してシャッフル再生


ステップ1 リスト登録したBGMを順番にループ再生する


PlayerのPrefabを修正する。

AudioSource
Play On Awake OFF
Loop OFF

これで自動再生はOFFになるので、スクリプトで再生を制御する。

HierarchyでPlayerのPrefabを選ぶ。

C#スクリプト BGMSelector を追加する。

Playerの BGMSelector のAudioClipsのスロットにBGMをリスト登録する。

以下のコードで audioClipsのアクセス修飾子がprivate になっているが[SerializeField]アトリビュートを設定することでUnity Editorに接続できる。(これまでのアクセス修飾子をpublicにした場合と同様)。

配列の要素数の取得はC#では配列名が array のとき

array.Length

と書く

曲を順番に再生するために曲の再生終了をチェックするコルーチン Checking を用意する。

Checkingで順番に曲を再生するためにBGMPlayメソッドを用意して再帰呼び出し(無限ループ)にした。

参照記事:

UnityのSEが鳴り終わったタイミングで処理を実行する(callback) https://qiita.com/TakashiHamada/items/a5ff15ca7e63c06bfb23

AudioSourceの再生終了判定などのサウンド管理 https://deve-cat.com/audiosourcec-end-judgment/

UnityのInspectorで多次元配列 https://hacchi-man.hatenablog.com/entry/2020/03/01/220000

ステップ2 曲順をシャッフルする

参照: シャッフルのアルゴリズム https://nekojara.city/unity-shuffle

C#の拡張メソッド https://ufcpp.net/study/csharp/sp3_extension.html

ここでC#の拡張メソッド Shuffle を定義した。

Shuffleは配列などに対して使用可能で、

array.Shuffle()

により、arrayの要素の並び順をランダムに入れ替える。


BGMSelectorを修正する

Startメソッドに曲順をシャッフルするコードを追加

        // 配列をシャッフル

        audioClips.Shuffle();


C#拡張メソッドを定義するクラスを追加する。
※BGMSelectorクラスのメンバーではない。クラス定義の下にコードを追記すること。

※クラスの中のクラスインナークラスを定義することもC#では可能だが、ここでは使えない。

(ステップW)リピート再生で全曲の再生が完了した時に、再シャフルして再生順を毎回異なるようにする。最後の曲が再生されたときに再シャッフルするコードを追加すればよい。

(ステップV)再シャッフルの際に直前に再生した曲が連続しないようにシャッフルを調整する。再シャッフル前に最後の曲のAudioClipを記録、シャッフル後の先頭の曲と同じになるなら再シャッフルを繰り返す。

ゲームのサウンド全体にエフェクトをかける

AudioListenerにフィルターを設定

AudioMixerのエフェクト設定

リバーブ効果風呂場や洞窟の残響)をBGMとSE※に設定する。
※BGMまたはSEの片方だけに設定でもOK

Prefab PickUp Audio Source Output SEに設定

Prefab NorthWall Audio Source Output SEに設定


Audio Mixerのパネルから、

BGM のAddボタン → SFX Reverb を追加

SE のAddボタン → SFX Reverb を追加

音響設定をPresetに2つ登録する。

Snapshot+ボタン を押  CAVE と入力して追加

Snapshot+ボタン を押 ROOM と入力して追加

1つ目の音響設定を調整

CAVEを選択

Room を 0.00mB(ミリバール)に調整


参照「Unity SFX Reverb Effect プリセットメモ」各パラメータの意味

SFX Reverbの設定(歯車アイコン)から Allow Wet Mixing を ON にする。

Audio Mixerの BGM か SE を選択

パラメータをさらに調整する(上記の設定では効果が分かりにくいため)

Wet 0.00 dB

Room -1000 mB

Room HF -1000 mB

Reverb 1000.00 mB 音割れしてもいいなら 2000.00 mB

さらに

Dry Level -10000 mB

Reflections 1000mB

してもよいかも

変更前

変更後

(オプション)

Audio Mixerの BGM か SEで上で設定していない方を選択

パラメータをさらに調整する(上記の設定では効果が分かりにくいため)

Wet 0.00 dB

Room -1000 mb

Room HF -1000 mb

Reverb 1000.00 mb 音割れしてもいいなら 2000.00 mb

2つ目の音響設定を調整

ROOMを選択

右クリック → Set as start Snapshot

でゲームのデフォルト音響設定として設定する。

SFX Reverb のパラメータは調整せずに元のままでOK

変更なし

(オプション)Pitch Shifterエフェクトを追加

Audio MixerのPitch(緑枠)を調整すると 再生速度が変化する

Pitch ShifterのPitch(赤枠)を調整すると 再生速度を維持して音程が上下する

スクリプトによる音響設定の変更

リバーブ効果の適用方法A

SnapShotの切り替え処理をC#スクリプトで行う 参照記事
Triggerの範囲を設定してSnapshotを切り替える。

リバーブ効果の適用方法B

UnityのReverbZoneを設定する※ 参照記事
※BGMのAudioClipをステージの床などに設定してリバーブのかかる範囲を設定する方法


方法Aを紹介

ReverbController.cs を作成

 シーンにTrigger範囲を設置してAudioMixerの設定(Snapshots)を切り替えるようにする。

スクリプトをPrefabPlayerにアタッチして、スクリプトのスロットにミキサーのスナップショットを設定する。

Trigger範囲をシーンに追加:

Hierarchyから3D Objectの Cubeを追加する。
Position と Scale を調整
Mesh Renderer OFF
Is Trigger を ON

Tagを「ReverbZone」に設定

(オプション)

Trigger範囲をシーンに追加:

Hierarchyから3D Objectの Shereを追加する。
Position と Scale を調整
Is Trigger を ON

Tagを「ReverbZone」に設定

(ステップU)残響の発生する範囲に地形を追加する

Hierarchyに Terrain(地形)を追加
Asset Store(要Unityの個人アカウント)からTerrain Toolkit2017をパッケージインポートして地形をセット

 記事参照 https://www.sejuku.net/blog/70742

動的なSE

 ボールの転がるスピードに応じて効果音を変化させる。

効果音は 効果音ラボから借用など https://soundeffect-lab.info/sound/button/


 スクリプト PitchShifter.cs を用意する。

 スクリプトをPlayerのPrefabにアタッチする。

  このスクリプトでPlayerの運動の状況を調べ、効果音の再生ピッチ(速度)を速度に応じて調整する。
調整用の計算式でMathf.Sqrtで速度のルートを求めている。
この式では、速度の0.0から1.0の変化に対してピッチは急上昇する。
微速の場合でも音を鳴らしたいので。

効果音はLoop設定している。
Playerの速度が0の場合はピッチも0になり音は出なくなる。
効果音に無音区間があると、音の再生に間隔が生じる。


 AudioSource を PlayerのPrefabに追加する。※

※これはPlayerの2個目のAudioSourceになる。
※Inspectorで、既にアタッチされているAudioSourceよりも下に位置させる必要がある。 参照記事:https://mrstar-memo.hatenablog.com/entry/2014/01/01/154159

このコードでは GetComponents でAudioSourceを取得している。
今まで使用してきたGetComponent ではない。
GetComponents は同種の複数のコンポーネントを配列で取得できるので、効果音を設定した2個目のAudioSourceを取得できる。

(ステップT)Playerが空中にいる場合は効果音を変える。着地状態を判定するスクリプトを参考にするとよい。

(ステップW)セリフ再生時にBGMとSEの音量を下げて聞き取りやすくする

 参照記事 https://zenigane138.hateblo.jp/entry/2018/02/20/225510

AudioListenerにフィルターを設定

AudioListenerをコンポーネントに持つゲームオブジェクト(Main Cameraなど)にフィルターを設定できる。

このフィルターはゲームの全サウンドに影響を与える。

※BGMやSEなどのチャンネルごとにフィルターを設定するには、AudioMixerを使う必要がある。


設定方法

Main Camera(AudioListenerを持つオブジェクト)を選択

Add Component -> Audio -> Audio Reverb Filter

Reverb Preset を選択する

反響効果を知覚しやすい物がよい

Bathroom 風呂場

Sewerpipe 下水管

Drugged 意識朦朧

PresetでUserを選択するとパラメーターを調整できる。

AudioListenerのAudioFilterはシーン再生中にパラメータの変更が反映される。

シーンを再生して効果を確かめるとよい。