Unity中的TimeLine支持自定义轨道,一般需要新建三个(若需要处理混合则为四个)类。官方教学视频
一、Track 1、用途 首先需要定义一个轨道类,继承TrackAsset,它代表了时间轴内的轨道。官方API
2、代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [TrackColor(0.055f, 0.03f, 0.387f) ] [TrackClipType(typeof(MyClip)) ] [TrackBindingType(typeof(Animator)) ] public class MyTrack : TrackAsset { [SerializeField ] int blendingDuration = 200 ; protected override Playable CreatePlayable (PlayableGraph graph, GameObject gameObject, TimelineClip clip ) { var asset = clip.asset as MyClip; asset.duration = blendingDuration; return base .CreatePlayable(graph, gameObject, clip); } }
3、轨道类可以被三种特性标签修饰
[TrackColor(float r, float g, float b)]用于定义轨道的颜色,方便不同轨道之间的区分;
[TrackClipType(Type clipClass)]用于指定在轨道中可创建的PlayableAsset类型,可以理解实现了轨道类型和片段类型之间的绑定,同一个轨道可以添加多种不同的片段类型,及可以有多个TrackClipType修饰同一个轨道类;
[TrackBindingType(Type type)]用于指定轨道需要绑定到的对象类型,如示例中的LookAtTrack是用于控制某个角色上的头部动画,因此需要绑定一个角色的Animator组件。若改轨道不需要绑定特定对象,则不需要添加该标签。
4、常用方法
protected override Playable CreatePlayable(PlayableGraph graph, GameObject gameObject, TimelineClip clip)
protected override void OnCreateClip(TimelineClip clip) 在新建片段时调用用于设置Clip的默认值。
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)当片段之间支持混合时可添加该方法。
二、Asset 1、用途 接着定义一个继承PlayableAsset、实现接口ITimelineClipAsset的类,用于表示片段资源,该类中可以定义片段包含的字段,这些字段会暴露到Inspector中。
2、代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class MyClip : PlayableAsset , ITimelineClipAsset { public string content; public ExposedReference<Transform> target; public DialogueBehaviour template = new MyBehaviour(); public ClipCaps clipCaps { get { return ClipCaps.None; } } public override Playable CreatePlayable (PlayableGraph graph, GameObject owner ) { var playable = ScriptPlayable<MyBehaviour>.Create(graph, template); var myBehaviour = playable.GetBehaviour(); myBehaviour.content = content; myBehaviour.target = target; return playable; } }
3、常用方法 通常该类中会重写CreatePlayable()方法,常用于实现该类和Behaviour类之间的数据传递,关于
ScriptPlayable 和 PlayableBehaviour的使用可参考ScriptPlayable 和 PlayableBehaviour - Unity 手册
三、Behaviour 1、用途 接着定义一个Behaviour类继承PlayableBehaviour用于描述片段中触发的行为。官方API
2、代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class MyBehaviour : PlayableBehaviour { private bool clipPlayed = false ; private bool pauseScheduled = false ; private PlayableDirector director; public override void OnPlayableCreate (Playable playable ) { director = (playable.GetGraph().GetResolver() as PlayableDirector); } public override void OnBehaviourPlay (Playable playable, FrameData info ) { if (!clipPlayed && info.weight > 0f ) { if (Application.isPlaying) pauseScheduled = true ; clipPlayed = true ; } } public override void OnBehaviourPause (Playable playable, FrameData info ) { if (pauseScheduled) { pauseScheduled = false ; clipPlayed = false ; director.Pause(); } } }
3、常用方法
PrepareFrame 循环播放刷新时调用
OnBehaviourPlay 进入该行为片段时调用
OnBehaviourPause 退出该行为片段时调用
OnPlayableCreate 创建时、编辑器模式选中Timeline时
OnGraphStart 创建后、播放时
OnGraphStop 停止时,编辑器模式选中其他对象时
OnPlayableDestroy 同上,在停止后调用
四、Mixer 若需要使轨道片段支持融合,则需要添加Mixer类,该类同样继承PlayableBehaviour
五、踩坑合集
Clip的遍历:Timeline没有提供快速定位到某一Clip的接口,要想定位只能遍历,而且要从轨道开始遍历,这让代码写起来非常恶心,需要嵌套多层循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 IEnumerable<TimelineClip> tempClips = null ; var playableAsset = director.playableAsset as TimelineAsset;foreach (var track in playableAsset.GetOutputTracks()){ if (track is MyTrack && !track.muted) { tempClips = track.GetClips(); foreach (var clip in tempClips) { if (clip.asset is MyClip b) { } } } }
对场景中对象的引用需要通过ExposedReference<T>创建,否则绑定完成的引用无法被Unity保存。对应的调用则需要通过Resolve(graph.GetResolver())解析出对象。
1 2 3 4 5 6 public ExposedReference<Transform> target;public override Playable CreatePlayable (PlayableGraph graph, GameObject owner ) { var target = target.Resolve(graph.GetResolver()); }