C++幼女先輩

プログラミング成分多め

CreatePlayable周りの調査。AssetからBehaviourを、BehaviourからBindingを参照したい

CreatePlayable周りがちょっとややこしかったので調査
まず初めに断っておくが、本来はMixerを作るのがベストだが、今回はあえてMixerを作らずに頑張ってみる

ScriptPlayable

        var playable = ScriptPlayable<NewPlayableBehaviour>.Create(graph);
        var trackBinding = go.GetComponent<PlayableDirector>().GetGenericBinding(this) as GameObject;
 
        playable.GetBehaviour().target_ = trackBinding;
        return playable;

前回はこのようにしてBehaviourにバインディングを渡した
もちろん、単なるプロパティ経由なのでどんなものでも渡せる

ただし、この場合 PlayableAsset::CreatePlayableが呼ばれない そのため、PlayableAssetがBehaviourを知る方法がメンドクサイなど問題が生じる
なので、この方式を変更しようと思う

TrackAsset::CreatePlayable

BaseClassのCreatePlayableを呼ぶと、その中からPlayableAsset::CreatePlayableが呼ばれるようになる
具体的には

NewPlayableTrack

return base.CreatePlayable(graph, go, clip);

Assetの方は下記コードで、Behaviourの参照を手に出来る
templateという変数名にするのが通例のようだ
今回は template_というプロパティーを持たせる

    public NewPlayableBehaviour template_;

    public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
    {
        return ScriptPlayable<NewPlayableBehaviour>.Create(graph, template_);
    }

前にコード書いたときは上記で、template_にBehaviourの参照が渡ってきた覚えがあるが
コード間違えたかUNITYのバージョンか覚え違いか、Nullだったので変更した

    public NewPlayableBehaviour template_;

    public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
    {
        var playable = ScriptPlayable<NewPlayableBehaviour>.Create(graph);
        template_ = playable.GetBehaviour(); 
        return playable; 
    }

これで確実にtemplate_にbehaviourが設定される

上記で対応できると思ったが、Inspectorを作る時に不具合が生じる。今のところUNITY2020で問題が起こっている・・
UNITY2020では異なる方法で行う必要があるかもしれないので
今後は少し古いが UNITY2019.4での作業に変更

Bindingを渡したい

BehaviourにてトラックにBindingされたオブジェクトの操作をしたい事は多々ある
が、UNITYのTimelineはBehaviourから簡単にBindingが参照できない(ほんとこれは不便)
なので、どこかでBindingを渡す必要がある

まずBindingの取得方法だが、TrackAsset::CreatePlayable あるいは、PlayableAsset::CreatePlayableの引数の
GameObjectが、タイムラインのGameObjectになっていて
そこからPlayableDirectorコンポーネントを取得し、その中のBindingsから該当するトラックのBindingを検索する
具体的なコードは

        var trackBinding = go.GetComponent<PlayableDirector>().GetGenericBinding(key) as GameObject;

もちろんこのgoがGameObjectだが、問題はこのKeyである
Directorから何らかの方法でKeyを取得できるかもしれないが
ここはTrackAssetのthisを渡すのが簡単なので、TrackAssetから渡したい

結果

NewPlayableTrack

[TrackBindingType(typeof(GameObject))]
[TrackClipType(typeof(NewPlayableAsset))]
public class NewPlayableTrack : TrackAsset
{
    protected override Playable CreatePlayable(PlayableGraph graph, GameObject go, TimelineClip clip)
    {
        Playable playable = base.CreatePlayable(graph, go, clip);
 

        var trackBinding = go.GetComponent<PlayableDirector>().GetGenericBinding(this) as GameObject;
        Debug.Log("Track::" + trackBinding);

        var p = (ScriptPlayable<NewPlayableBehaviour>)playable;
        p.GetBehaviour().binding_ = trackBinding;

        return playable;
    }
}

NewPlayableAsset

public class NewPlayableAsset : PlayableAsset
{
    public NewPlayableBehaviour template_;

    public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
    {
        var playable = ScriptPlayable<NewPlayableBehaviour>.Create(graph, template_);
        return playable;
    }
}

以上で
PlayableAssetからは templateという名前でBehaviourが扱え
PlayableBehaviourからは binding
という名前でトラックにバインドされたオブジェクトが扱える