今回はTimelineのデータ情報を流し込む方法についてです。
Timelineは使い回せる
Timelineのシーケンスを管理するPlayableAssetsは名前の通りアセットですので、複数のオブジェクトで使いまわす事が可能です。
これを上手く活用すると、特定のイベント…例えば「幅を飛び越える」や「宝箱を開ける」といった部分で、Timelineを活用したアニメーション制御やカメラワーク制御が使用できそうです。
TimelineとNavmeshの組み合わせ pic.twitter.com/l4dISADioG
— 椿 (@tsubaki_t1) 2017年4月23日
イベントに使う事でAnimatorの構造を簡単にする
これはTimelineによるモデルに対するアニメーション制御が可能な事を意味しています。なので、例えば「ドアを開ける」「ゲームオーバーになり倒れる」「階段を登る」等の、Animatorで制御すると面倒な(ステートのスパゲティを引き起こしやすい)問題が回避しやすくなります。
ちなみにTimelineのアニメーション流し込みはPlayableAPIを使用しているので、Timelineを使用したくないならPlayableAPIで流し込んでも良いです。
使い回しTimelineを作る時は編集用シーンを用意するが吉
Unity 2017b2で治ってるかもしれませんが、以下のような事があるので、使い回しTimelineを作る時は編集用シーンを作ったほうが良いです。
- エディタ操作時のTimelineでシーケンス操作した後に元に戻す機能がスーパー雑
- アニメーションはPlayableDirectorではなく親オブジェクトからの相対座標指定で動く
特に2番めの問題があるので、RootMotionが無いキャラクターを移動させるモーションを作る場合は、キャラクターを載せて動かすダミーオブジェクトを用意するのが良さそうです。
Timelineはバインドしたオブジェクトを操作する
Timelineを使いまわす上で重要なのが、オブジェクトのバインドです。
Timelineは基本的にバインドしたオブジェクトを操作します。その為、複数のTimelineが合った場合でも操作する操作する対象を分ける事が出来ます。
例えば上のアニメでは初回のジャンプだけカメラワークの位置が異なります。これは個別にカメラワークの位置を設定出来るために可能な表現です。
PlaybleDirectorがオブジェクトへの参照を保持し、Timelineはその情報を使う
Timelineを使う上でのデータのバインドは、多くの場合下のように設定されています。つまり、トラックに露出した項目に設定します。
これをPlayable Directorで見るとBindingsの項目にTimelineで設定したコンポーネントが表示されています。
もしTimelineを複製した際、異なるオブジェクトをバインドしたい場合、PlayableDirectorで参照先を変えてやると、動かす対象が変化します。
つまりTimelineの参照関係解決の流れは、こんな感じという事です。
- Playable Directorにシーン内のオブジェクトへの参照を保持しておく
- 実行時、PlayableAssetの情報を元にTrackやAsset、Playable*1を生成
- Playable Directorが参照情報をTrackやAssetに参照を流し込む
- AssetがPlayableに参照を流し込み、参照情報を使って再生する
ちなみにInspectorに表示される項目は設定中にPlayableAssetsの項目ですが、複数のPlayableAssetsの項目が保持出来ます。
これで動的にPlayableAssetsを流し込んだ場合も、バインド機能は動作するという事です。
別シーンのオブジェクトや生成したオブジェクトは動的にバインドする
この参照関係の構築の問題はTimelineが別シーンであったり、動的に生成している場合です。これらは事前に参照関係を設定出来ないので、動的にオブジェクトをバインドする必要があります。
PlayableTrackに動的なオブジェクトをバインドする
まずはトラックにバインドします。
PlayableAssetsがバインド可能な項目は、PlayableAssets.outputsから取得出来ます。そこからトラック名が一致するPlayableBindingを取得します。これがPlayableAssetのトラックへの鍵となります。
あとはPlayableDirector.SetGenericBindingで、PlayableDirectorにバインド情報を流し込みます。*2
なおトラック名とはTimelineのトラック選択時にInspectorに出てくるコレです
PlayableAssetに動的なオブジェクトをバインドする
アセットにオブジェクトをバインドします。
こちらは一々個別に設定など出来ないので、Resolverで参照を解決してもらいます。ただExposedReferenceではなく、割とマニュアルな感じです。
PlayableAssetのバインドはIExposedPropertyTable経由で保持されている物を使用しています。つまりIExposedPropertyTableにキーとバインドするオブジェクトを与えてやれば良い訳です。
ここでExposedReferenceを使いたい所ですが、ExposedReferenceが設定するキーの値がちょっと分からないので、キーは手前側で勝手に決めてしまった物を使います。
- playableDirector.SetReferenceValueでオブジェクトをバインドする。
- graph.resolver.GetReferenceValueでバインドしたオブジェクトを取り出す。
なんでC#のDictionalyでやらないのかという意見があるかもしれませんが、私もそう思います。まぁTimelineの中身がほぼC++っぽいので、こういう形なんでしょうが…