Timelineを拡張して、自由にプロパティをコントロールする4つの方法をまとめました。
- はじめに
- まずはお手軽にMonoBehaviourのプロパティをコントロール
- ITimeControlを実装するだけで既存クラスがTimelineに対応
- ちゃんとやるならPlayableTrack用のカスタムクリップを作る
- カスタムトラックから作ればブレンドも可能に
- 参考サイト
- 関連
Unity2018.3.9
はじめに
この記事ではUnityのTimelineで独自のクリップやトラックを作る方法をまとめます。
Timelineの基本的な使い方は次の記事を参照してください。
またカスタムクリップやカスタムトラックを作成する場合にはPlayable APIの基礎知識が前提となりますが、
Playable APIについては次の記事にまとめています。
まずはお手軽にMonoBehaviourのプロパティをコントロール
さて一点目は最もシンプルな方法です。
まずpublicなプロパティを定義し、LateUpdate()でそれを反映するようなMonoBehaviourを作ります。
using UnityEngine; public class Example : MonoBehaviour { public float Rotation { get; set; } // TimelineがUpdateで値を反映するのでLateUpdateで値を適用する public void LateUpdate() { transform.rotation *= Quaternion.AngleAxis(Rotation, Vector3.up); } }
これをAnimation Trackで動かすだけです。
PostEffectなど、Animationから直接触れられないプロパティをコントロールするのによさそうです。
ITimeControlを実装するだけで既存クラスがTimelineに対応
二つ目はITimeControlを使う方法です。
まずITimeControlを実装したMonoBehaviourを作成します。
using UnityEngine; using UnityEngine.Timeline; public class Example : MonoBehaviour, ITimeControl { /// <summary> /// クリップに入った時に呼ばれる /// </summary> public void OnControlTimeStart() { gameObject.SetActive(true); } /// <summary> /// クリップから出た時に呼ばれる /// </summary> public void OnControlTimeStop() { gameObject.SetActive(false); } /// <summary> /// クリップがアクティブな時に毎フレーム呼ばれる /// </summary> public void SetTime(double time) { transform.rotation *= Quaternion.AngleAxis(Mathf.Pow((float)time, 2.0f), Vector3.up); } }
このスクリプトを適当なGameObjectにアタッチしておきます。
そしてControlTrackのにこのGameObjectをセットします。
するとTimelineからITimeControlのメソッドが呼ばれるようになります。
この方法も実装はシンプルですが、detaTimeやクリップの長さなどが取れないので複雑な処理はできません。
ちゃんとやるならPlayableTrack用のカスタムクリップを作る
次にPlayableTrack用のカスタムクリップを作る方法です。
クリップを作るにはPlayableBehaviourを継承したクラスとPlayableAssetを継承したクラスを作ります。
まずPlayableBehaviourを継承したクラスのソースコードです。
using UnityEngine; using UnityEngine.Playables; public class ExamplePlayableBehaviour : PlayableBehaviour // PlayableBehaviourを継承する { public Renderer Renderer { get; set; } public Color StartColor { get; set; } public Color EndColor { get; set; } private Material _material; // フレーム毎の処理 // 非ランタイムでも呼ばれるので注意! public override void ProcessFrame(Playable playable, FrameData info, object playerData) { if (_material == null && Renderer != null) { _material = new Material(Renderer.sharedMaterial); Renderer.sharedMaterial = _material; } if (_material == null) { return; } var progress = (float)(playable.GetTime() / playable.GetDuration()); _material.color = Color.Lerp(StartColor, EndColor, progress); } }
PlayableBehaviourにはフレームごとの処理を定義します。
一点注意が必要なのが、Timelineは非ランタイムでも呼ばれるということです。
非ランタイムで呼ばれても問題ないような書き方をする必要があります(上記の例はちょっと適当ですが)。
次にPlayableAssetを継承したクラスを作ります。
using UnityEngine; using UnityEngine.Playables; public class ExamplePlayableAsset : PlayableAsset { [SerializeField] private ExposedReference<Renderer> _renderer; [SerializeField] private Color _startColor; [SerializeField] private Color _endColor; public override Playable CreatePlayable(PlayableGraph graph, GameObject owner) { // PlayableBehaviourを元にPlayableを作る var playable = ScriptPlayable<ExamplePlayableBehaviour>.Create(graph); // PlayableBehaviourを取得する var behaviour = playable.GetBehaviour(); // 参照を解決する behaviour.Renderer = _renderer.Resolve(graph.GetResolver()); behaviour.StartColor = _startColor; behaviour.EndColor = _endColor; return playable; } }
PlayableAssetはTimeline上の1つのクリップ情報を表すものです。
先ほど作ったPlayableをインスタンス化して返すメソッドを持ちます。
これでPlayable TrackのメニューにAdd Example Playable Asset
が追加されるのでこれを選択します。
こんな感じで色を変更するクリップが作れました。
カスタムトラックから作ればブレンドも可能に
最後に紹介するのがトラックからカスタムする方法です。
この方法は最も自由度が高く、重なったクリップ同士をブレンドしたりもできます。
ただしその分定義するクラスも多くなります。
そのためこの方法の詳細は別の記事としてまとめていますのでこちらをご覧ください。