自定义轨道需要创建以下资产

TrackAsset/PlayableAsset/PlayableBehaviour

1.TrackAsset

可创建CustomTrack继承自TrackAsset, 之后就可以在Timeline编辑界面创建CustomTrack轨道

在定义CustomTrack时,相关特性(Attribute)需要关注

[TrackClipType(typeof(XXXAsset))]  表示其轨道上可以添加什么类型的Asset

[TrackBindingType(typeof(Transform/GameObject/Animator))] 表示其轨道上可以绑定什么样的游戏节点(比如AnimationTrack绑的是Animator)

可单独创建自定义轨道(无对应的自定义PlayableAsset/PlayableBehaviour), 比如只需要绑定节点的情况

image

 

2.PlayableAsset

可创建CustomPlayableAsset继承自PlayableAsset,并定义相关可序列化的属性

在Timeline编辑界面设置后,运行时可透传至PlayableBehaviour

public class CustomPlayableAsset : PlayableAsset
{
    public string beginMark = string.Empty;
    public string endMark = string.Empty;
    public string jumpMark = string.Empty;

    public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
    {
        var playable = ScriptPlayable<CustomPlayableBehaviour>.Create(graph);
        var pb = playable.GetBehaviour();
        pb.PD = owner.GetComponent<PlayableDirector>();
        pb.beginMark = beginMark;
        pb.endMark = endMark;
        pb.jumpMark = jumpMark;
        return playable;
    }
}

 

image

3.PlayableBehaviour

可创建CustomPlayableBehaviour继承自PlayableBehaviour,运行时获取到jumpMark等属性,并在播放至该帧时获取信息执行逻辑

    public class CustomPlayableBehaviour : PlayableBehaviour
    {
        public string beginMark = string.Empty;
        public string endMark = string.Empty;
        public string jumpMark = string.Empty;
        public PlayableDirector PD { get; internal set; }

        public override void OnBehaviourPlay(Playable playable, FrameData info)
        {
            if (PD != null && PD.playableGraph.IsValid())
            {
                if (!string.IsNullOrEmpty(jumpMark)) { } // jump to jumpMark
            }
        }
    }

4.创建、获取Group信息

Timeline编辑界面可以按如下操作创建组,并重命名

image

 运行时可以获取组信息

PlayableDirector director = xxx;
TrackAsset track;
foreach (var output in director.playableAsset.outputs)
{
    // 将输出转换为TrackAsset
    track = output.sourceObject as TrackAsset;
    if (track != null)
    {
        var group = track.GetGroup();
        if (group != null && group.name == "XXX") { }//TODO
    }
}

5.运行时获取、重置轨道绑定信息

以CustomTrack为例

定义时其头部标记了特性

[TrackBindingType(typeof(Transform))]

因此运行时可以获取该轨道上绑定的Transform

PlayableDirector director = xxx;
CustomTrack track = xxx;// 可以从director.playableAsset.outputs的sourceObject里找到Track
Transform parent = director.GetGenericBinding(track) as Transform;
// 重置绑定
director.SetGenericBinding(track, newTransform);

还可以替换动画剪辑

        AnimationTrack track = xxx;
        // 重新绑定AnimationClip
        var clips = track.GetClips();
        foreach (var clip in clips)
        {
            AnimationPlayableAsset asset = clip.asset as AnimationPlayableAsset;
            if (asset != null) asset.clip = newClip;// 可通过原 clip.displayName 找到要替换的clip
        }

从Animator里根据动画剪辑名找clip

RuntimeAnimatorController controller = animator.runtimeAnimatorController;
foreach (AnimationClip c in controller.animationClips)
{
    if (c.name == clipName) //TODO
}

 

6.根据CustomTrack实现自定义播控逻辑

public static void PlayTimeline(PlayableDirector director, string aniName)
{
    double timeToJump = -1;
    CustomTrack ctrlTrack = null;
    foreach (var output in director.playableAsset.outputs)
    {
        // 将输出转换为TrackAsset
        ctrlTrack = output.sourceObject as CustomTrack;
        if (ctrlTrack != null)
        {
            var clips = ctrlTrack.GetClips();
            foreach (var clip in clips)
            {
                CustomPlayableAsset asset = clip.asset as CustomPlayableAsset;
                if (asset != null && asset.beginMark == aniName)
                {
                    timeToJump = (float)clip.start;
                    break;
                }
            }
            break;
        }
    }
    if (timeToJump >= 0)
    {
        director.time = timeToJump;
        director.Play();
    }
}

 

注:绑定信息不保存在timeline资源里,轨道上的帧信息会保存在timeline资源里