テラシュールブログ

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

【Unity】Timeline × Cinemachine でカットシーンのカメラワークを作る

f:id:tsubaki_t1:20170615220517g:plain

今回はCinemachine を使用してカメラワークを設定してみます。

Cinemachine

Cinemachineは「指定したオブジェクトがカメラの何処に映ってほしいのか」と「複数カメラ座標・設定のブレンド」機能を持ったカメラリグです。

tsubakit1.hateblo.jp

例えば下の図だと、黄色いドットが被写体の位置、青で指定してる範囲が被写体が映る位置です。このカメラ設定だと、被写体がどのように動いても右下に映るように設定されています。

f:id:tsubaki_t1:20170615221152j:plain

またカメラの位置や設定(Vertual Camera)を設定・ブレンドする事で、複数のカメラを切り替える事が出来ます。

下の図の場合、1カメラから2カメラへ、2カメラから3カメラへ…といった形でカメラを切り替えています。また、切り替える際、二つのカメラをブレンドする形で切り替える事も出来ます。

f:id:tsubaki_t1:20170615221410j:plain

 

TimelineとCinemachineを使ってみる

Timelineと組み合わせてみます。

Cinemacine TrackCinemachine Brainを追加してCameraの設定

まずはCinemachine.Timeline > Cinemacine Trackでトラックを追加します。Trackが要求する物はCinemachine Brain(Cinemachineのカメラ制御するコンポーネント)なので、無ければ追加します。

f:id:tsubaki_t1:20170615221616j:plain

f:id:tsubaki_t1:20170615221805j:plain

Cinemachine vertual cameraはカメラの座標と設定

Cinemachine vertual camera(カメラの座標や向き、FOVやLookat等の設定)を使って、実際のカメラの位置を調整します。

この機能を使用するとScene上で設定したカメラ位置は無視される点に注意して下さい。

 

 Cinemacine Trackのシーケンス調整する所を右クリックして、Add Cinemachine Shot Clipを追加します。

追加されたらVirtual Cameraを設定しますが、無ければCreateで作成します。Virtual Cameraはショット(カメラワーク)の数だけ作る感じです。

f:id:tsubaki_t1:20170615222222j:plain

f:id:tsubaki_t1:20170615222248j:plain

位置には「CM」が表示されるので、分かりやすいです。

f:id:tsubaki_t1:20170615222541j:plain

カメラのブレンドはTimelineで

カメラをブレンドします。

二つのシーケンスを混ぜればOKです。ドラッグ&ドロップで重なるように移動すれば、ブレンドする設定になります。

重なる幅が広ければ広いほどゆるやかに、狭ければ狭いほど急激に変化します。全くブレンドしたくない場合は、重ならないようにすれば一瞬で切り替わります。

f:id:tsubaki_t1:20170615222722j:plain

f:id:tsubaki_t1:20170615223537g:plain

カメラが見る場所はLookAtとAim

カメラが見るべき場所を指定します。Look Atに見たいオブジェクトを指定、AimをComposerに設定します。

f:id:tsubaki_t1:20170615223739j:plain

後はカメラが映すべき場所に範囲を指定します。枠はGameViewをドラッグすれば、大きくしたり小さくしたり出来ます。

また映すべき対象の中央をドラッグすれば、位置をズラす事が出来るので、画面左端や右端に被写体を写したい場合は、これで動かします。

f:id:tsubaki_t1:20170615223659g:plain

注意すべきは、この操作を行うためにはTimelineで指定のカメラを使用しているかつTimelineでシーケンスを選択している必要があります。

つまり、下のような状態です。上はP4を選択中かつTimelineでP4を再生中なので、編集が可能です。下はP4を選択していますがTimelineがP4を再生する位置に居ないので、編集出来ません。

f:id:tsubaki_t1:20170615224235j:plain

Cinemachineの入手

Cinemachineの入手ですが、現在はフォーラムで公開されています。

将来的にはAssetStoreに移動したり、Unity Engineに統合されるかもしれません。

https://forum.unity3d.com/threads/cinemachine-v2-0-final-release-candidate-loads-of-new-features.476510/

 

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

【Unity】逆引き自動レイアウトのトレーニング。UIをLayoutGroupで並べる

f:id:tsubaki_t1:20170615020246j:plain

今回は自動レイアウトの動作を把握するために、色々とトレーニングしてみました。

自動レイアウトでUIを並べる

UIの要素を並べる場合、HorizontalLayout GroupやVertical Layout Groupといったレイアウト調整機能を使用するのが便利です。

ただ、この動作は割とわかりにくいと評判(主観)です。なので、下の記事である程度の解説を行いましたが、今回は実際に色々と並べてみようと思います。

tsubakit1.hateblo.jp

なお、今回のレイアウトシステムは全てHorizontalLayoutを使用しますが、動作的にはVertical Layoutも似たようなものです。

UIのサイズが固定、もしくは親に合わせて子のサイズが変動する場合は、簡単

UIのサイズが固定だったり、親のサイズに合わせて子のサイズが変動するような場合、並べるのは割と楽です。

Imageを並べる(左から詰める)

単純にSpriteを並べる場合です。並べる際には、左から順番に詰めるように並べます。

f:id:tsubaki_t1:20170614233730g:plain

  1. 適当にCanvasを作る。
  2. CanvasにHorizontalLayoutGroupを設定する。
    その際、Control Child SizeやChild Force Expandは外す
    Child AlignmentはMiddle Left(左の中央)を設定
  3. Image付きSpriteを作る(×沢山)

f:id:tsubaki_t1:20170614234007j:plain

これで、左からUIの大きさに合わせて詰めて並べる挙動になります。生成するImageの大きさ調整を行う設定になっていないので、レイアウトによっては画面外にUIが飛び出したり、逆に余白が生まれるといった事になるかもしれません。

なお、この設定ではRectTransformのサイズを見ます。つまり、UIの大きさによって詰め具合が変わります。

f:id:tsubaki_t1:20170614234810g:plain

また各Imageにスペースが欲しい場合は、Spacingを少し増やします。

 

Imageを並べる(等間隔)

f:id:tsubaki_t1:20170614235312g:plain

UIを等間隔に生成します。

  1. 適当にCanvasを作る。
  2. CanvasにHorizontalLayoutGroupを設定する。
    その際、Child Force Expandにチェックを入れる
    Child AlignmentはMiddle Center(中央)を設定
  3. Image付きSpriteを作る(×沢山)

Child Force Expandにチェックが入っている(初期設定)ので、等間隔に並びます。入り切らない場合、枠の外にはみ出ます。Control Child Sizeにチェックが入っていないので、Imageの大きさは変化しません。

f:id:tsubaki_t1:20170614235645j:plain

高さにフィットしたUIを並べる

f:id:tsubaki_t1:20170615000315g:plain

レイアウトは必ずしも固定とは限りません。
例えばAndroid端末のアスペクト比はカオスですし、iPadはアプリを分割して起動出来ますし、Androidもアプリをウィンドウモードで起動できます。

ので、UIの高さもある程度フレキシブルな事が望ましいといえば望ましいです。

  1. 適当にCanvasを作る。
  2. CanvasにHorizontalLayoutGroupを設定する。
    その際、Child Force ExpandとControl Child SizeのY軸にチェックを入れる
    Child AlignmentはMiddle Left(中央左)を設定
  3. Image付きSpriteを作る(×沢山)

f:id:tsubaki_t1:20170615000759j:plain

Y軸はUIの大きさと一致するレベルで広がりますが、X軸のサイズはRectTransformのサイズで動きます。

 

なお、上下に余白を付けたい場合はPaddingを設定します。

f:id:tsubaki_t1:20170615000941j:plain

 

大きさが固定なUIを並べる

大きさが固定なUI(幾つかのImageを組み合わせたもの)を並べます。

f:id:tsubaki_t1:20170615001522g:plain

まず下のようなUIを作成します。割とごく普通の、よくある構成のUIです。RectTransformの下にImageが3つ。

f:id:tsubaki_t1:20170615001819j:plain

後は「Imageを並べる(左から詰める)」と同じ要領です。

 

  • 適当にCanvasを作る。
  • CanvasにHorizontalLayoutGroupを設定する。
    その際、Control Child SizeやChild Force Expandは外す
    Child AlignmentはMiddle Left(左の中央)を設定
  • UIを作る(×沢山)

上記の設定ではRectTransformの設定でオブジェクトが並べられるので、レイアウトはシンプルに並びます。

勿論、大きさを変更することも可能です。

f:id:tsubaki_t1:20170615212141g:plain

子の大きさを元にUIのサイズが変動する場合は、面倒くさい

逆に子の大きさが固定ではなく、子の大きさに従ってUIのサイズが決まる場合、割と面倒な事になります。具体的には、UIの大きさを自動レイアウトで調整する必要性が出てきます。

子のUIの大きさが変動するUIを並べる(子のmin=Perferred)

「子のUIの大きさが変動するUI」を並べてみます。まずはmin = Perferred…つまり大きさの基準がImageの場合です。

f:id:tsubaki_t1:20170615005624g:plain

この動作では、UIの大きさを変更してしまえば「大きさが固定なUIを並べる」と同じように設定出来るのですが、それが難しい場合はLayout Groupに大きさを調整してもらいます。

  1. 適当にCanvasを作る。
  2. CanvasにHorizontalLayoutGroupを設定する。
    その際、Control Child Sizeにチェックを入れ、Child Force Expandのチェックは外す
    Child AlignmentはMiddle Left(左の中央)を設定
  3. UIを作り、UIのトップはHorizontalLayoutGroupを設定。Control Child Sizeにチェックを入れる
  4. UIの次の階層にHorizontalLayoutGroupを設定。Control Child Sizeにチェックを入れない。4の子にImageを作成。適当な大きさにする

f:id:tsubaki_t1:20170615010723g:plain

Control Child Sizeが入っていると、子のPerferredのサイズを元にRectTransformを変更します。

子から親へPerferredの値にPaddingを足してPerferredのサイズを調整、親から子にPerferredの値を元にRectTransformを調整しています。なので、最後(大きさの変わるUI)の親にはControl Child Sizeにチェックが入っていません。

子のUIの大きさが変動するUIを並べる(子のmin≠Perferred)

次にlayout elementのminとperferredが一致しない場合です。

f:id:tsubaki_t1:20170615004934g:plain

具体的に言えばTextです。Textはperferredは文字が全て入るサイズになりますが、minの大きさは0です。またRectTransformとperferredのサイズが一致しない点もあります。

 

  1. 適当にCanvasを作る。
  2. Canvasの子を作成
  3. 2のオブジェクトにHorizontalLayoutGroupを設定する。
    その際、Control Child Sizeにチェックを入れ、Child Force Expandのチェックは外す。
    Child AlignmentはMiddle Left(左の中央)を設定
  4. UIを作り、UIのトップはHorizontalLayoutGroupを設定。Control Child Sizeにチェックを入れる
  5. UIの次の階層にHorizontalLayoutGroupを設定。Control Child Sizeにチェックを入れる。
  6. 5の子にTextを作成

f:id:tsubaki_t1:20170615012051g:plain

「子のUIの大きさが変動するUIを並べる(子のmin=Perferred)」と異なり、UIの大きさはTextが生成するPerferredの値を元にレイアウトを調整します。なので、下から二番目のLayoutGroupもControl Child Sizeにチェックが入っています。

 

ただ忘れてはいけないのがminのサイズは0という事です。なので、範囲内にUIが入り切らなかった場合、UIの大きさが変動してしまいます。

f:id:tsubaki_t1:20170615013256g:plain

これを回避するアイディアで思いつくのは二つ。

一つはContent Size FitterでPerferredと同じ大きさに一番親のオブジェクト(今回で言うならCanvasの下のRoot)のサイズを変更してしまう事。これで「入り切らなくてUIが縮まる」事は無くなります。なにせ、足りなくなったら親が大きくなる訳ですから。

もう一つが、minのサイズをPerferredのサイズにしてしまう事。これでminが0では無いので圧縮されることはなくなります。

gist.github.com

f:id:tsubaki_t1:20170615014251j:plain

これでオブジェクトが隅っこに到達しても、UIが潰れる事は無くなりました。

f:id:tsubaki_t1:20170615014759g:plain

 

感想

自動レイアウトの復習でした。

とりあえず「任意のサイズのUIを並べる」だけなら簡単なんですが、Textのように子のサイズを元にレイアウトを決める場合、面倒なことになります。

印象としては下な感じです。

  • 子から親にサイズ情報を渡し、それを元に親レイアウトは自身のサイズを決める
  • 親レイアウトグループが子のRectTransformを調整する

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

 

 

 

【Unity】2D Experimental Preview Release 4のタイルマップ デモが楽しそう

2D Experimental Preview Releaseの4が(だいぶ前に)公開されてました。

https://forum.unity3d.com/threads/2d-experimental-preview-release-4.469914/

f:id:tsubaki_t1:20170615025550j:plain

今回はプレビューリリースの他にデモプロジェクト「RoboDash 」が付いてます。

www.youtube.com

動画には無いですが、光表現とか結構悪くないように見えます。*1

*1:いいから早く出ろ

【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があるシーン。