テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】ボタンを押したら音が出る…を、出来る限りコードを書かずに実現する

f:id:tsubaki_t1:20170613224436j:plain

今回は、ボタンを押した際に音を出す方法を聞かれたので、ココにも書いておきます。音の制御というよりは「ボタンを押した時に音を出したい」という要望を叶える為の物です。

ボタンを押したら音が出る

自分が小学生の頃、ボタンを押したら音が出る(あと光る!)玩具で遊んだ事を覚えています。

ボタンを押したら「ジョインジョインドゥ」みたいな音が出る剣とか、ボタンを押したら「パラリパラリラパラリパラリラ(トゥーーーーン)」みたいな音が出るベルトとか。

ゲームでも、大抵のボタンを押すときは何らかの音が出ます。今回はこの動作を、出来るだけコードなしでチャレンジしてみようと思います。

Audio Soureceはスピーカー、Audio Listenerは耳

音は、概ねAudio Source、Audio Listener、Audio Clipの3つの項目から成り立ちます。Audio Sourceが音を発信し、Audio Listenerが音を聞き取ります。Audio Clipは再生する音の種類です。

f:id:tsubaki_t1:20170613225350j:plain

ソースは発信源なので、設定によっては距離や(Listenerとの)相対速度等が表現に影響するかもしれません。

今回は音場の全く関係ない2D設定で話を進めます。

AudioSource.PlayOneShotで音を再生する。…ボタンから

オーディオを流すAPIAudioSource.PlayOneShotです。このAPIでAudio Clipを指定してやれば、音が再生されます。

 

…で、実はこのAPI、ButtonのOnClickで指定出来ます。

ButtonのOn Click(Unityのイベントシステム)では、パブリックかつ戻り値がvoidかつ引数が一つ(シリアライズ可能)なAPIはエディター上で指定する事が出来るので、AudioSourceのPlayOneShotは呼び出すことが出来ます。

その際に引数に出したい音を指定してやれば、ボタンをおした時に指定した音が出ます。

f:id:tsubaki_t1:20170613230001j:plain

実際の手順

まずAudioSourceを用意します。複数の音源があっても一つのAudioSourceで良いです。SE用として使いまわします。

f:id:tsubaki_t1:20170613230437j:plain

 

Buttonを用意して、OnClickの「」を押します。

f:id:tsubaki_t1:20170613230807j:plain

 

None(Object)に先程作成したAudio Sourceを登録、NoFunctionAudioSource.PlayOneShotを設定します。

f:id:tsubaki_t1:20170613230832j:plain

 

あとはNone(AudioClip)の所に再生したいAudioClipを登録すれば完了です。これでボタンを押せば音がなります。

f:id:tsubaki_t1:20170613231050j:plain

 

Gifには音が出ないのでAudio Mixerで音が出てるのを確認します。

f:id:tsubaki_t1:20170613231152g:plain

クリック以外で音を鳴らす場合はEvent Triggerで呼ぶ

上の例だと「クリック時」に音がなります。ソレ以外のケース、例えば「マウスカーソルがボタンの上に乗った」みたいなタイミングで音を出してみます。

クリック以外のタイミングは、Event Triggerで呼び出します。

f:id:tsubaki_t1:20170613231516j:plain

 

例えば「ボタンの範囲内に入ったら音が出る」の場合、Add New EventTypeでボタンをクリック後、Pointer Enterを選択、後は上でやってたようにボタンにイベントを登録するだけです。

f:id:tsubaki_t1:20170613231629j:plain

f:id:tsubaki_t1:20170613231923g:plain

AudioSourceが違うシーンだったり、ボタンを動的に作ってる場合

UIを複数のシーンで跨いで作成していたり、UIをPrefab化して動的に生成してる場合、Cross Scene Reference問題*1で、単純に参照関係を構築出来ない場合があります。

 

で、色々と考えましたが、ScriptableObjectを経由して参照関係を構築する方法を思いつきました。Audio Manager(Scriptable Object)にAudio Sourceを登録して、ボタンのイベントで呼び出してもらう方法です。

f:id:tsubaki_t1:20170614000458j:plain

ScriptableObjectの「アセット」を用意

まず、二つのスクリプトを用意します。

AudioManager は、AudioSourceをScriptableObjectに登録して、登録したAudioSourceのPlayOneShotを呼び出すScriptableObject、

MonoBehaviourEventTriggerは、AwakeとDestroyのタイミングで登録したメソッドを呼び出す汎用コンポーネントです。

gist.github.com

まずはScriptableObjectのアセットを用意します。*2。名前は別になんでも良いですが、AudioManagerとしました。

f:id:tsubaki_t1:20170613233833j:plain

 AudioSourceを登録

次に、AudioSourceをAudioManagerに登録する挙動を追加します。

MonobehaviourEventTriggerOnAwakeのタイミングに、AudioManagerを設定、AudioManager.audioSourceAudioSourceコンポーネントを設定します。

AudioManager.audioSourceはプロパティですので、イベントに使用出来ちゃいます。

これで、Audio Sourceオブジェクトがロードされると、AudioManagerにAudio Sourceコンポーネントが自動的に登録されます。

f:id:tsubaki_t1:20170613234006j:plain

 ボタンを押したらScriptableObjectを経由して音が出る

ボタンを押した際に音が出る設定も行います。

AudioSourceは直接参照出来ないので、ButtonにはAudioManagerを登録します。

AudioManagerのPlayOneShotは、AudioSourceと同じように任意の音を登録。

f:id:tsubaki_t1:20170613234441j:plain

 

これでボタンとAudioSouceが揃った時、即座に音が鳴るようになりました。

下の例では、ボタンをシーンに生成すると、ボタンとAudioSourceが繋がって、ボタンを押した際に音が出るようになってます。

f:id:tsubaki_t1:20170613234830g:plain

雑記

もう少し複雑な動作を期待するならスクリプトを書いた方が良いでしょうが、ボタンを押して音を出す演出くらいなら、UIのレベルで運用出来たららくじゃない? という感じで作ってみました。

関連

qiita.com

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

*1:他のシーンにあるオブジェクトや、Prefab(アセット)からシーン内のオブジェクトを参照できない問題

*2:このアセットは個人的には、MonoBehaviourEventTrigger等で登録するシーンのフォルダに配置するのがベータかなと考えてます。つまり今回の場合はAudioSourceがあるシーン。