UNITYタイムライン PlayableTrackとBinding
PlayableTrack
プログラマとしては本題!
独自の処理をするトラックを作ります
用途はほんと色々あります
だいたい仕事では8割以上はこのカスタムトラックでタイムライン作るかも
Track、Asset、Behaviour、Mixerの4つで構成されます
PlayableTrack
カスタムのClipを入れる事のできるトラックです
UNITYから用意されているPlayableTrackをそのまま使う事も可能ですが
独自のバインディングやら初期化処理などを行う場合には自分で作ります
というか、自分で作りましょう
PlayableAsset
クリップ
実行時にインスタンス化するための情報を保持したりしている
実行時に下記のBehaviourをCreateする
PlayableBehaviour
インスタンス化したあとの実際のふるまいを定義する
カスタムトラックの肝
Mixer
上記のBehaviourの一種
クリップ同士(複数のBehaviour)をブレンドする事ができます
実際に作ってみる
Assets->Create->Playables
で、BehaviourとAssetのスクリプトのテンプレートが作成できる
PlayableAsset
[System.Serializable] public class NewPlayableAsset : PlayableAsset { // Factory method that generates a playable based on this asset public override Playable CreatePlayable(PlayableGraph graph, GameObject go) { return Playable.Create(graph); } }
上記のような何もしないテンプレートが作成される
PlayableBehaviour
public class NewPlayableBehaviour : PlayableBehaviour { // Called when the owning graph starts playing public override void OnGraphStart(Playable playable) { } // Called when the owning graph stops playing public override void OnGraphStop(Playable playable) { } // Called when the state of the playable is set to Play public override void OnBehaviourPlay(Playable playable, FrameData info) { } // Called when the state of the playable is set to Paused public override void OnBehaviourPause(Playable playable, FrameData info) { } // Called each frame while the state is set to Play public override void PrepareFrame(Playable playable, FrameData info) { } }
こちらは、コールバックのみのBehaviourが作成されました
BehaviourとAssetを連結させる
とりあえずPlayableTrackを作りクリップを作成する
今回はNewPlayableAssetという名前なのでそれを作成します
先ほどのBehaviourのコールバックにログを仕込んでも、まだ連結させてないのでコールバックが来ません
なので接続しましょう
AssetのCreatePlayableにて、今は汎用的なPlayableを作成していますが、それを自作のBehaviourにします
public override Playable CreatePlayable(PlayableGraph graph, GameObject go) { return ScriptPlayable<NewPlayableBehaviour>.Create(graph); }
これで、今回作ったNewPlayableBehaviourが呼ばれるようになり、ちゃんとコールバックが呼ばれるように
ScriptPlayable
public struct ScriptPlayable<T> : IPlayable, IEquatable<ScriptPlayable<T>> where T : class, IPlayableBehaviour, new() { public static ScriptPlayable<T> Null { get; } public static ScriptPlayable<T> Create(PlayableGraph graph, int inputCount = 0); public static ScriptPlayable<T> Create(PlayableGraph graph, T template, int inputCount = 0); public bool Equals(ScriptPlayable<T> other); public T GetBehaviour(); public PlayableHandle GetHandle(); public static implicit operator Playable(ScriptPlayable<T> playable); public static explicit operator ScriptPlayable<T>(Playable playable); }
IPlayableBehaviourを持つBehaviourをCreateしたり。
GetBehaviourとかGetHandleとかもしかして使うかもね
PlayableTrack
TrackAssetから派生する
[TrackClipType(typeof(NewPlayableAsset))] public class NewPlayableTrack : TrackAsset { protected override Playable CreatePlayable(PlayableGraph graph, GameObject go, TimelineClip clip) { Playable playable = base.CreatePlayable(graph, go, clip); return playable; } }
TrackClipTipeにカスタムのAssetを指定する
先ほどつくったPlayableTrackを削除し、今度は今作ったカスタムTrackを作成
そのトラック上で右クリックをすると、先ほど作ったNewPlayableAssetのクリップを作成できる
TrackBinding
カスタムトラックにオブジェクトをバインディングできます アトリビュートを追加
[TrackBindingType(typeof(GameObject))] [TrackClipType(typeof(NewPlayableAsset))]
他にもトラックの色を変えたりアトリビュートがある
TrackBindingを設定すれば指定したオブジェクトに対して影響を与えるトラックが作れます
今回はGameObject型にしていますが、Animatorを設定したり出来る
TrackBindingにシーン上のCubeを指定しよう
TrackBindingの取得
ここが非常に昔から不満点ですが
UNITYのTimelineではBehaviourからTrack情報を取得するのが難しいです
クリップの開始は OnBehaviourPlayのコールバックで取得しますがそのプロトタイプは
public override void OnBehaviourPlay(Playable playable, FrameData info)
となっており、トラックの情報が取れません
なので以下の3パターンで取得する事になります
Behaviour#ProcessFrameで取得
ProcessFrameだけはプロトタイプが
public virtual void ProcessFrame(Playable playable, FrameData info, object playerData);
となっており、playerDataにBindingが入っているのでCastすればよいです
public GameObject target; public virtual void ProcessFrame(Playable playable, FrameData info, object playerData) { target = playerData as GameObject; }
ただし、ProcessFrameは毎フレーム呼ばれる処理です。最初のフレーム時のみtargetを取得するように改造が必要ですが
そもそも初期化時に設定すればいいものを毎フレーム処理したくありません
Mixerを作りMixerのOnBehaviourPlay時に渡す
今回はMixerを作っていないので省略しますが
わりと見ますね
ただし、Mixerを作る必要があるのでMixer不要な場合は手間です
TrackのCreatePlayable時に渡す
今回はこれでいきます
Trackのコードを
protected override Playable CreatePlayable(PlayableGraph graph, GameObject go, TimelineClip clip) { var playable = ScriptPlayable<NewPlayableBehaviour>.Create(graph, 1); var trackBinding = go.GetComponent<PlayableDirector>().GetGenericBinding(this) as GameObject; playable.GetBehaviour().target = trackBinding; return playable; }
CreatePlayableで渡ってきたGameObjectからPlayableDirectorを取得し、そこからBindingを取得して
作成したBehaviour(Playable)に渡す
これでOK