テラシュールブログ

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

【Unity】Timelineに動的に生成したオブジェクトをバインドする

f:id:tsubaki_t1:20170426221416g:plain

今回はTimelineのデータ情報を流し込む方法についてです。

 

※Unity 2017b5で実装が大幅に変わった為、動作しません。
 新しい実装に修正中

 

Timelineは使い回せる

Timelineのシーケンスを管理するPlayableAssetsは名前の通りアセットですので、複数のオブジェクトで使いまわす事が可能です。

これを上手く活用すると、特定のイベント…例えば「幅を飛び越える」や「宝箱を開ける」といった部分で、Timelineを活用したアニメーション制御やカメラワーク制御が使用できそうです。

イベントに使う事でAnimatorの構造を簡単にする

 これはTimelineによるモデルに対するアニメーション制御が可能な事を意味しています。なので、例えば「ドアを開ける」「ゲームオーバーになり倒れる」「階段を登る」等の、Animatorで制御すると面倒な(ステートのスパゲティを引き起こしやすい)問題が回避しやすくなります。

ちなみにTimelineのアニメーション流し込みはPlayableAPIを使用しているので、Timelineを使用したくないならPlayableAPIで流し込んでも良いです。

使い回しTimelineを作る時は編集用シーンを用意するが吉

Unity 2017b2で治ってるかもしれませんが、以下のような事があるので、使い回しTimelineを作る時は編集用シーンを作ったほうが良いです。

  1. エディタ操作時のTimelineでシーケンス操作した後に元に戻す機能がスーパー雑
  2. アニメーションはPlayableDirectorではなく親オブジェクトからの相対座標指定で動く

特に2番めの問題があるので、RootMotionが無いキャラクターを移動させるモーションを作る場合は、キャラクターを載せて動かすダミーオブジェクトを用意するのが良さそうです。

Timelineはバインドしたオブジェクトを操作する

Timelineを使いまわす上で重要なのが、オブジェクトのバインドです。

Timelineは基本的にバインドしたオブジェクトを操作します。その為、複数のTimelineが合った場合でも操作する操作する対象を分ける事が出来ます。

例えば上のアニメでは初回のジャンプだけカメラワークの位置が異なります。これは個別にカメラワークの位置を設定出来るために可能な表現です。

f:id:tsubaki_t1:20170426210833j:plain

PlaybleDirectorがオブジェクトへの参照を保持し、Timelineはその情報を使う

Timelineを使う上でのデータのバインドは、多くの場合下のように設定されています。つまり、トラックに露出した項目に設定します。
これをPlayable Directorで見るとBindingsの項目にTimelineで設定したコンポーネントが表示されています。

もしTimelineを複製した際、異なるオブジェクトをバインドしたい場合、PlayableDirectorで参照先を変えてやると、動かす対象が変化します。

f:id:tsubaki_t1:20170426203915j:plain

f:id:tsubaki_t1:20170426204040j:plain

つまりTimelineの参照関係解決の流れは、こんな感じという事です。

  1. Playable Directorにシーン内のオブジェクトへの参照を保持しておく
  2. 実行時、PlayableAssetの情報を元にTrackやAsset、Playable*1を生成
  3. Playable Directorが参照情報をTrackやAssetに参照を流し込む
  4. AssetがPlayableに参照を流し込み、参照情報を使って再生する

 

ちなみにInspectorに表示される項目は設定中にPlayableAssetsの項目ですが、複数のPlayableAssetsの項目が保持出来ます。
これで動的にPlayableAssetsを流し込んだ場合も、バインド機能は動作するという事です。

別シーンのオブジェクトや生成したオブジェクトは動的にバインドする

この参照関係の構築の問題はTimelineが別シーンであったり、動的に生成している場合です。これらは事前に参照関係を設定出来ないので、動的にオブジェクトをバインドする必要があります。

f:id:tsubaki_t1:20170426205659j:plain

PlayableTrackに動的なオブジェクトをバインドする

まずはトラックにバインドします。

PlayableAssetsがバインド可能な項目は、PlayableAssets.outputsから取得出来ます。そこからトラック名が一致するPlayableBindingを取得します。これがPlayableAssetのトラックへの鍵となります。

あとはPlayableDirector.SetGenericBindingで、PlayableDirectorにバインド情報を流し込みます。*2

gist.github.com

なおトラック名とはTimelineのトラック選択時にInspectorに出てくるコレです

f:id:tsubaki_t1:20170426212248j:plain

PlayableAssetに動的なオブジェクトをバインドする

アセットにオブジェクトをバインドします。

こちらは一々個別に設定など出来ないので、Resolverで参照を解決してもらいます。ただExposedReferenceではなく、割とマニュアルな感じです。

 

PlayableAssetのバインドはIExposedPropertyTable経由で保持されている物を使用しています。つまりIExposedPropertyTableにキーとバインドするオブジェクトを与えてやれば良い訳です。
ここでExposedReferenceを使いたい所ですが、ExposedReferenceが設定するキーの値がちょっと分からないので、キーは手前側で勝手に決めてしまった物を使います。

  1. playableDirector.SetReferenceValueでオブジェクトをバインドする。
  2. graph.resolver.GetReferenceValueでバインドしたオブジェクトを取り出す。

gist.github.com

なんでC#のDictionalyでやらないのかという意見があるかもしれませんが、私もそう思います。まぁTimelineの中身がほぼC++っぽいので、こういう形なんでしょうが…

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

*1:PlayableTrackやPlayableAsset

*2:Inspectorは変化しません。