今回はUnityのAudio Mixerを使ってみようと思います。
今回の記事を作成する際にUnityのチュートリアルを参考にさせて頂きました。
Audio Mixerとは個別の音声を変換したり調整したりするものです。
今まではゲームオブジェクトにコンポーネントのAudio Sourceを取りつけて音声を鳴らすだけでしたが、オーディオミキサーを使用するとBGMやSEなどを個別に管理し、
音声の調整をする時に便利になります。
個別のAudio Sourceのパラメータをスクリプトで調整する事も出来ますが、オーディオミキサーを使用するとより直感的な調整が可能です。
↑のような感じでBGMと効果音を別のグループとして取り扱い、管理する事が出来るようになります。
トンネル内では音が反響するような効果を与えるようにしています。
Audio Mixerを作成する
まずはAudio Mixerを作ってみましょう。
ProjectフォルダのAssetsフォルダ内で右クリック→Create→Audio Mixerを選択して作成します。
↑のようにAudio Mixerとその中にMaster、Snapshotが作成されました。
Audio Mixerを選択するとインスペクタでThreshHold Volume(閾の音量?)が設定出来ます。
これは何に使うのが現時点では不明です・・・・(^_^;)
Masterを選択するとPitch(音声の再生スピード)、AttenuationのVolume(音量)を変更出来ます。
ここで設定を変更すれば音声のスピードと音量を手動で変更する事が出来ます。
ただ現時点ではオーディオミキサーを作っただけで取りつけていないので何も起きません。
AudioSourceにAudioMixerを設定する
それではAudio Sourceにオーディオミキサーを設定してみましょう。
の記事で音声の鳴らし方についてやりましたのでそちらを参考にAudio Sourceを設定してください。
BGMを設定するゲームオブジェクトを作成しAudio Sourceを取りつけます。
BGMはMainCameraに設定でいいかもしれません。
もちろんAudio Sourceを設定するゲームオブジェクトはご自分の環境に合わせて設定してかまいません。
むしろわたくしと同じ設定をする必要はまったくありません(^^)/
UnityのメニューのWindowからAudioMixerを選択します。
AudioMixerのグループの作成
次にBGMとSEの音声グループを分ける為に新しいグループを作成します。
↑の赤い部分をクリックし新しいグループを2つ作ります。
名前をBGMとSEとしておきます。
階層は必ずMasterの下になります。
BGMとSEは同階層にしたいのでSEがBGMの子になっている場合はドラッグしてMasterの上でドロップさせます。
AudioSourceにBGMグループを設定
次にAudio Source(BGMを設定したもの)のOutputにBGMグループをドラッグ&ドロップします。
このAudio SourceはBGMとして使用する為にSpatial Blendを一番左にドラッグし完全に2D音声にします。
3D音声にすると音声を設定したゲームオブジェクトからAudio Listenerを設定したゲームオブジェクト(デフォルトでMainCameraに設定)が離れると音が小さくなるので、
MainCamera自体にAudio Sourceを取りつけるか、2D音声にしておくといいと思います。
壁にぶつかった時の効果音グループSEをAudioSourceに設定
次に効果音を設定しましょう。
プレイヤーキャラクターが壁とぶつかった場合に効果音を鳴らすようにします。
プレイヤーキャラクターはCharacterControllerで動かすので、相手方と衝突したかどうかはキャラクター側でOnControllerColliderHitメソッドを実装して衝突を検知するようにします。
OnControllerColliderHitメソッドはCharacterControllerで動かしているキャラクターが他のコライダを持つゲームオブジェクトと接触した時に呼ばれるメソッドです。
ゲームステージにヒエラルキー上で右クリック→3D Object→Cylinderを作り名前をWallとします。
壁は衝突出来るようにCapsule ColliderのIs Triggerのチェックが外れている事を確認してください。
またキャラクターが衝突した時に壁と認識させる為、Wallというタグを作成し設定しておきます。
次にWallに効果音を設定します。
Add ComponentでAudio Sourceを追加し、Audio Clipに鳴らしたい効果音を設定してください。
Outputには先ほど作ったAudio MixerのSEを設定します。
↑のように音声、Outputの設定をし、PlayOnAwakeのチェックを外しゲームオブジェクト登場時に音声が鳴らないようにします。
またSpatial Blendを右側にドラッグし3D音声にしておきます。
3D音声の他の設定は自由に変更してください。
キャラクターが壁と衝突した時に実行するスクリプトCollisionWallの作成
キャラクターには壁と衝突した事を確認するスクリプトCollisionWallを作成し取りつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using UnityEngine; using System.Collections; public class CollisionWall : MonoBehaviour { // CharacterControllerを使ってキャラクターを動して他の物体と衝突したら呼ばれるメソッド void OnControllerColliderHit(ControllerColliderHit col) { // 相手がWallタグを持つゲームオブジェクトであれば音声を鳴らす if(col.gameObject.tag == "Wall") { var audioSource = col.gameObject.GetComponent <AudioSource> (); // 1音声の再生 // audioSource.Play (); // 接触した回数だけ再生(音が重なる) audioSource.PlayOneShot (audioSource.clip); } } } |
キャラクターがWallタグを持つゲームオブジェクトと接触した時に音声を鳴らしています。
AudioSourceのPlayメソッドを呼ぶと音声を鳴らす事が出来ます。
Playメソッドの場合は1回だけ音声が再生されますが、PlayOneShotにすると衝突している間は何重にも音声が再生されます。
今回のサンプルではPlayOneShotを使う事にします。
銃を撃つ等の連続した音声再生をする時はPlayOneShotの方がいいのかも?
音声はWallゲームオブジェクトに設定したAudio Sourceを取得し、そのAudio Sourceの音声クリップを再生します。
BGM、キャラクターが壁にぶつかった時のSEを確認
とりあえず音声の設定が終わったので実行ボタンを押してBGMが鳴るかどうか、壁にぶつかった時に効果音が鳴るかどうかを確認しましょう。
実行中にAudioMixerタブを開くと↑のようにグループ毎にグラフが表示されます。
Edit In Play Modeを押すと実行中に音声の設定を変更する事が出来ます(実行をやめても結果が反映されるので注意してください)。
↑の例ではMasterの音量を下げるとBGM、SEに設定されている音量も一緒に下がります。
これはBGM、SEはMasterの子だからです。
またBGMやSEそれぞれの音量を下げるとそれぞれのグループだけ音量が下がるという感じになります。
これでAudioMixerのグループを使ってそれぞれのグループの音量が下げられる事がわかったと思います。
別のゲームオブジェクトに設定しているAudio SourceのOutputにもこれらのグループを設定すると同じように操作出来ます。
音声設定を作成する
次に音声設定画面を使って音量を調整出来るようなUIを作成してみましょう。
音声設定画面UIの作成
まずはCanvasを作成し名前をSoundOptionとします。
その子要素にPanelの階層を作り、このPanelは画面いっぱいのサイズより少し小さめに作ります。
BGM用とSE用のTextとSliderをそれぞれ作成しています。
実際のUIは↑のようになりました。
音声設定スクリプトSoundOptionを作成
次にこの音量設定画面を開いたり閉じたりする為にMainCameraにSoundOptionという名前で新しくスクリプトを作成して取りつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using UnityEngine; using System.Collections; using UnityEngine.Audio; using UnityEngine.UI; public class SoundOption : MonoBehaviour { // SoundOptionキャンバスを設定 [SerializeField] private GameObject soundOptionCanvas; void Update () { // 4が押されたらUIをオン・オフ if(Input.GetKeyDown("4")) { soundOptionCanvas.SetActive(!soundOptionCanvas.activeSelf); } } } |
インスペクタでSoundOptionのUIを設定出来るようにし、キーボードの4が押されたらSoundOptionUIをオン・オフするようにしています。
これで音量設定画面のオン・オフが出来るようになりました。
最初はオフの状態にしたいのでSoundOptionゲームオブジェクトは手動でオフの状態にしておいてください。
これでSoundOption画面のオン・オフが出来るようになりました。
音声の調整を出来るようにする
次はSoundOption画面が表示された時に全体の音声を少し落としてみましょう。
SnapShotを使って音声の状態を変更する
これを行う為にSnapShotを使ってみます。
SnapShotは音声設定を施した状態でいくつか作っておき、切り替える事で音声の状態を変えたい時に便利です。
写真のスナップとかと同じでその状態を作成しておき切り替える事が出来る機能ですね。
↑の赤い部分をクリックし新しいスナップショットを作成します。
SoundOption画面を表示している時はOptionSoundShot、表示していない時はGameSoundShotを使うようにします。
OptionSoundShotを選択しMasterの出力を-10dbに設定します。
GameSoundShotだとMasterの出力が0dbでOptionSoundShotだとMasterの出力が-10dbになります。
ここで一旦SoundOption画面のSliderの設定値を変更します。
音量操作する時のAudioMixerのラベルは最大で20db、最低で-80dbとなっています。
そこでBGM、SEの音量調整出来る値の範囲を-80~20に設定しておきます。
BGMSlider、SESliderのMinValue、MaxValueを-80、20と設定します。
これでスライダーの調整が終わりました。
SnapShotの切り替え処理をSoundOptionスクリプトに追加
次にSoundOption画面を開いた時にOptionSoundShot、閉じた時にGameSoundShotの状態へと変化させます。
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 | using UnityEngine; using System.Collections; using UnityEngine.Audio; using UnityEngine.UI; public class SoundOption : MonoBehaviour { // SoundOptionキャンバスを設定 [SerializeField] private GameObject soundOptionCanvas; // GameSoundShot [SerializeField] private AudioMixerSnapshot gameSoundShot; // OptionSoundShot [SerializeField] private AudioMixerSnapshot optionSoundShot; void Update () { // 4が押されたらUIをオン・オフ if(Input.GetKeyDown("4")) { soundOptionCanvas.SetActive(!soundOptionCanvas.activeSelf); if(soundOptionCanvas.activeSelf) { optionSoundShot.TransitionTo(0.01f); } else { gameSoundShot.TransitionTo(0.01f); } } } } |
AudioMixerSnapshotのフィールドを宣言し、画面のオン・オフに応じてそれぞれの状態へと変更しています。
TransitionToで遷移までの時間を設定しています。
画面のオン・オフで音量が変わるか確認してみてください。
音量の設定画面でこの機能を使うと設定画面を開いた時にスナップショットで音量を下げた事になり、その状態の時にBGM、SEの音量を調整している為、
ちょっとおかしなことになります。(^_^;)
現在はまだスライダーを移動させても音量を変化させていないので問題はありませんが、調整出来るようになるとおかしい事に気づきます。
BGM等の音量を上げて音量設定画面をオフにすると爆音が響きわたるようになります。
音量調整画面ではスナップショットで音量は下げない方がいいかもしれません。
普通のオプション画面とかだとかなり有効だとは思いますけどね。
BGM、SEのスライダーを動かし音量の調整をする
さて、次はBGM、SEのスライダーを動かした時にAudioMixerを通じて音量の調整をしていきます。
AudioMixerグループのVolume設定
まずスクリプトで音量を調整出来るようにAudioMixerのグループのVolume設定を変更します。
BGMとSEのグループを選択してインスペクタでVolume表記がある辺りで右クリックし↑の赤い部分を選択します。
これでスクリプトからAudioMixerの音量を変更する為の設定が出来ます。
AudioMixerタブの右側のExposed Parametersに先ほど設定したVolumeの設定が表示されるようになります。
名前をダブルクリックか選択状態でF2キーを押すと名前を変更する事が出来ますので、わかりやすい名前に変更します。
後はスクリプトからこの設定値を変更する事でAudioMixerの音量が変わるようになります。
音量調整処理をSoundOptionスクリプトに追加
SoundOptionスクリプトに音声調整処理を追加します。
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 | using UnityEngine; using System.Collections; using UnityEngine.Audio; using UnityEngine.UI; public class SoundOption : MonoBehaviour { // SoundOptionキャンバスを設定 [SerializeField] private GameObject soundOptionCanvas; // GameSoundShot [SerializeField] private AudioMixerSnapshot gameSoundShot; // OptionSoundShot [SerializeField] private AudioMixerSnapshot optionSoundShot; [SerializeField] private AudioMixer audioMixer; void Update () { // 4が押されたらUIをオン・オフ if(Input.GetKeyDown("4")) { soundOptionCanvas.SetActive(!soundOptionCanvas.activeSelf); if(soundOptionCanvas.activeSelf) { optionSoundShot.TransitionTo(0.01f); } else { gameSoundShot.TransitionTo(0.01f); } } } public void SetMaster(float volume) { audioMixer.SetFloat("MasterVol", volume); } public void SetBGM(float volume) { audioMixer.SetFloat("BGMVol", volume); } public void SetSE(float volume) { audioMixer.SetFloat("SEVol", volume); } } |
AudioMixerをインスペクタで設定出来るようにし、SetFloatでさきほど設定した名前に受け取ったパラメータの値を設定します。
受け取るパラメータはSliderを動かした時にスライダーの値を渡すので、スライダーの値が音量に設定される事になります。
スライダーを動かした時にSoundOptionスクリプトのメソッドを呼ぶ
それではBGMSlider、SESliderが動かされた時にこのSoundOptionスクリプトのそれぞれのメソッドが呼ばれるようにしましょう。
OnValueChangedイベントはスライダーをスライドして値が変わった時に呼ばれるイベントなのでここにMain Cameraゲームオブジェクトに設定しているSoundOptionスクリプトの該当するメソッドを設定します。
Sliderを動かした時に設定するのはDynamic floatのメソッドを指定します。
Dynamic floatのSetBGMやSetSEメソッドを呼び出すようにするとスライダーの値がそのままメソッドの引数に渡されます。
BGMSliderはSetBGM、SESliderはSetSEメソッドを設定します。
これで機能が完成しました。
Unityを実行しスライダーを動かしてBGMや効果音の音量が変わる事が確認出来ると思います。
トンネル内では反響するような音声効果を付けてみる
それでは最後にトンネルに入った時に反響するような機能を作成してみましょう。
トンネルの作成
まずはトンネルをCubeを組み合わせて作ります。
↑のように空オブジェクトを作り、名前をTonnelとします(突き抜けてないから洞穴が正解かも・・・)。
その子要素にCubeを繋ぎ合わせ空間を作ります。
トンネルの中にはさきほど作った主人公がぶつかったら効果音が鳴る壁をコピーし配置します。
空オブジェクトを作り名前をTonnelEffectとし、Add ComponentからBox Colliderを追加します。
Box Colliderの大きさを調整しIs Triggerにチェックを入れます。
↑のようにTonnelEffect空間をトンネルに進入した事を検知するエリアとして使います。
先ほどのTonnelの子要素に設置し忘れましたが・・・、トンネルを出る時のエリアもTonnelEffectと同じように作ります。
名前をNormalEffectとします。
それぞれの空間に進入したらAudioMixerのSnapshotを変更し効果音のエフェクトの効果を変更するという感じになります。
トンネル内での音声効果をAudioMixerで設定する
次にトンネル内では効果音に対してエコーをかける効果をつけたいと思います。
新しくAudioMixerを作りSoundの上にドラッグ&ドロップして子要素にします。
すると↑のように新しいウインドウが開くのでSoundの効果音のグループであるSEを選択します。
↑のようにSoundオーディオミキサーの子要素にSEグループのTonnelSoundオーディオミキサーが出来ました。
ここでなぜSEグループの子要素にしたかというとさきほど作成した音量調整の結果をこのTonnelEffectにも反映させる為です。
TonnelEffectはSEの子要素なのでSEの音量が下げられた時に同じようにTonnelEffectの音量も下がるようになります。
↑のように左の赤い部分をクリックして新しいグループであるCollisionとEchoを作成します。
右の赤い部分のAddをクリックしてCollisionにはSend、EchoにはEchoとReceiveを追加します。
CollisionのSendを選択し、インスペクタでCollisionのSendの受け取りグループを選択します。
SendにはEchoのReceiveを設定します。
これでCollisionの音声が鳴った時にReceiveを設定したEchoに音声が流れていきEchoの効果が発揮されるようになります。
SendにReceiveを設定するとSend levelが表示されます。
これがデフォルトで-80dbとなっており現時点ではReceiveには出力されていません。
今回のサンプルでいくと通常はEchoを効かせない効果音を鳴らし、トンネル内ではEchoを効かせたいので
Send levelを調整した二つのスナップショットを作成しましょう。
これを使ってEchoの効果の切り替えを行います。
↑の赤い部分をクリックしスナップショットを作成します。
通常状態のNormalとトンネル内のEdhoを作成します。
NormalのSnapShotを選択し、CollisionのインスペクタのSend levelを-80dbにしてEchoグループへの出力はしないようにします。
EchoのSnapShotを選択し、CollisionのインスペクタのSend levelを0dbにし、Echoへの出力を行います。
これで2つのスナップショットが作成出来ました。
主人公に設定した衝突した時の音声を鳴らすAudio SourceのOutputにCollisionを設定しておきます。
トンネル内外のスナップショット切り替えを行うChangeEffectスクリプトの作成
次はトンネル進入エリアTonnelEffectとトンネル外進入エリアNormalEffectにスナップショットを切り替えるスクリプトChangeEffectを作成します。
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 | using UnityEngine; using System.Collections; using UnityEngine.Audio; public class ChangeEffect : MonoBehaviour { [SerializeField] private AudioMixer mixer; [SerializeField] private AudioMixerSnapshot[] snapshots; // 接触した空間の番号 [SerializeField] private int triggerNum; void OnTriggerEnter(Collider col) { if(col.tag == "Player") { // 効果音にエコーを効かせる空間 if(triggerNum == 1) { mixer.TransitionToSnapshots (snapshots, new float[] {0f, 1f}, 1); Debug.Log("エコー"); // 通常の空間 } else if(triggerNum == 2) { mixer.TransitionToSnapshots(snapshots, new float[] {1f, 0f}, 1); Debug.Log("通常"); } } } } |
進入エリアにPlayerタグを持つゲームオブジェクトが入ってきたら進入エリアに設定されている番号を元にスナップショットを切り替えます。
トンネル進入エリアにはtriggerNumに1を設定し、トンネル外進入エリアにはtriggerNumに2を設定します。
オーディオミキサーのTransitionToSnapshotsで第1引数に指定したスナップショットのウエイトを第2引数で設定し、第3引数の秒で遷移させます。
snapshotsはスクリプトのインスペクタで設定出来、Element0にはNormalグループ、Element1にはEchoを設定するとします。
効果音にエコーを効かせるにはNormalのウエイトを0にしEchoのウエイトを1にして完全に切り替えます。
0と1と極端にしなくても0.5fと0.5fとするのも出来るみたいです。
逆にエコーを効かせない時はウエイトをさきほどとは反対に設定しています。
TonnelEffectとNormalEffectの進入エリアにChangeEffectスクリプトを設定し↑のようにパラメータを設定します。
TonnelEffectのtriggerNumは1、NormalEffectのtriggerNumは2を設定します。
またTonnelEffectオーディオミキサーのEchoグループのReceiveをドラッグしEchoより上に移動させてください。
受け取りを先にしないとエコーが発生しませんでした。
トンネルの中と外で音声が変わるか確認する
これで完成です。
Unityを実行して確認してみましょう!
と意気込みましたが、音声がないので効果音にエコーがかかっているかどうかの証明動画だけになります(^_^;)
↑のように通常の障害物にぶつかった時はEchoに出力がされず、トンネル内の障害物とぶつかった時はEchoに出力がされています。
屋内と屋外で効果音の鳴らし方を変えたい場合は有効な手段ですね!
AudioMixerはなんとなく難しそうな感じがして触っていなかったのですが、そんなに難しすぎるという事はありませんでした。
有効に使えているかどうかはともかく使ってみるという経験が出来たのはよかったかも(^^)v
終わりに
記事を書き終えてから2カ月ほど放置して本日公開となりました。
2カ月近く見てなかったのでほとんど記事の内容忘れてしまいましたよ・・・・(^_^;)
はぁ・・・また一から勉強し直さないといかんなぁ・・・(+_+)
忘却曲線を意識しながら定期的に勉強しないといけませんね。