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を記録、シャッフル後の先頭の曲と同じになるなら再シャッフルを繰り返す。
ゲームのサウンド全体にエフェクトをかける
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を選択
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(赤枠)を調整すると 再生速度を維持して音程が上下する
スクリプトによる音響設定の変更
スクリプトをPrefabのPlayerにアタッチして、スクリプトのスロットにミキサーのスナップショットを設定する。
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をパッケージインポートして地形をセット
動的な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の音量を下げて聞き取りやすくする
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はシーン再生中にパラメータの変更が反映される。
シーンを再生して効果を確かめるとよい。