Unity之TimeLine自定义

前言

playableAPI推出后,一直没有起色,记得当初Unity大会上,说是为了解放unity的动画系统,因为其操作之复杂枯燥,本应该美术同学的工作要强加给技术,所以当时果断放弃了。但是TimeLine的崛起,又回到我的面前。

四大天王

unity中样子

在这里插入图片描述

上面我们能看到的只要三个,还有一个混合器是我们看不到的,他也是timeLine的核心部分,他控制着片段之间的混合数据,以及timeline中计算好的数据应用到绑定物体上。

类关系结构

在这里插入图片描述

由上图可以出来Track和Clip(以下称呼为ClipAsset),都是一种资源。而Mixer和ClipPlayable是行为逻辑。

天王的关键函数

Track

  1. public virtual Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount);
    创建混合器,此方法我们可以重写实现我们自定义的混合器,如果我们没事重写,则会使用默认的混合器。通过此方法我们创建我们自定义的Mixer。
  2. public IEnumerable GetClips();
    获取轨道内的所有ClipAsset,其中TimelineClip.asset=ClipAsset。通过这个方法我们可以获取在Track中获取到ClipAsset。下面我们会知道通过ClipAsset可以获取到ClipPlayable的方式。
    通过以上两个方法我们可以从Track中获取到四大天王。
  3. [TrackColor(0.53f, 0.0f, 0.08f)] 属性:当前轨道的颜色
  4. [TrackClipType(typeof(“我们ClipAsset类型”))],属性: 当前轨道绑定的Clip类型
  5. [TrackBindingType(typeof(“输出的数据对象”))],属性: 在Mixer和ClipPlayable中的ProcessFrame函数中会以playerData的形式传递进去。
  6. public IEnumerable GetChildTracks();
    这个就是TrackGroup使用,很好理解。

ClipAsset

  1. public abstract Playable CreatePlayable(PlayableGraph graph, GameObject owner);
    ClipAsset实现此方法,并在方法中创建ClipPlayable。如果ClipPlayable中由数据的话可以对其进行初始化操作。
  2. struct ExposedReference where T : Object
    我们知道ClipAsset是资源,资源引用关系只能还是资源,如果引用了场景中的某个物体,则当timeLine加载时,那个引用关系就会丢失,所以使用ExposedReference在ClipAsset中声明需要引用的数据。而这个数据一般我们都会将其传递给ClipPlayable。
  3. ITimelineClipAsset实现此接口,用于描述片段的播放需求。此接口可选择性实现,也可以不实现,不实现默认的动画片段播放模式为ClipCaps.Blending。关于ClipCaps详见下面介绍。

Mixer

  1. public virtual void OnPlayableCreate(Playable playable) Playable 播放状态更改为 PlayState.Playing 时调用。最先执行的函数,如果勾选Play OnAwake则此帧只执行这一个函数,其他函数下一帧执行。如果用过PlayableDirctor.Play进行播放,则此函数和其他函数同帧执行。
  2. public virtual void OnGraphStart(Playable playable) 拥有此 PlayableBehaviour 的 PlayableGraph 启动时调用。
  3. public virtual void OnBehaviourPlay(Playable playable, FrameData info) Playable 播放状态更改为 PlayState.Playing 时调用
  4. public virtual void PrepareFrame(Playable playable, FrameData info) 当Playable状态为PlayState.Playting时,每帧调用
  5. public virtual void ProcessFrame(Playable playable, FrameData info, object playerData) 当Playable状态为PlayState.Playting时,每帧调用,在PrepareFrame之后执行,主要的行为处理逻辑。playerData为Track中[TrackBindingType(typeof(“PlayerData”))]的PlayerData。
  6. public virtual void OnBehaviourPause(Playable playable, FrameData info) Playable 播放状态更改为 PlayState.Paused 时调用。在PlayableDirctor.Pause调用后执行
  7. public virtual void OnGraphStop(Playable playable) 拥有此 PlayableBehaviour 的 PlayableGraph 停止时调用,PlayableDirctor.Stop或者销毁时调用
  8. public virtual void OnPlayableDestroy(Playable playable) 拥有 PlayableBehaviour 的 Playable 销毁后调用。PlayableDirctor.Stop或者销毁时调用,在OnGraphStop执行之后
  9. public virtual void OnBehaviourDelay(Playable playable, FrameData info) Playable 播放状态更改为 PlayState.Delayed 时调用。当playable.SetDelay之后执行,比如playableDirector.playableGraph.GetRootPlayable(0).SetDelay(3f);注意如果一个playable设置setdelay之后,其所有的输入playable都将设置同样的delay。
  10. public virtual void PrepareData(Playable playable, FrameData info) Playable 播放状态更改为 PlayState.Delayed 时调用。在setDelay后,delay的时间内,持续调用此函数,此时会停止调用PrepareFrame和ProcessFrame函数

以上函数是PlayableBehaviour的周期函数,以上说了调用时机和一些启动的函数。另外PlayState标识当前的状态,我们也可以通过GetPlayState(U playable) SetPlayState(U playable) 进行设置。注意两个概念:PlayableGraph和Playable。如果不懂的可以看看PlayableAPI或者直接记住用法即可。

ClipPlayable

和Mixer大体相似,只不过一些函数的执行时机不同。除了OnGraphStart和OnGraphStop这两个和PlayableGraph直接相关的一致外,其他的函数都是在当前Clip执行期间执行。

运行时Graph图结构

在这里插入图片描述
大部分情况下,我们自定义的都是类似于1,2(从左到右)两种Mixer的情况。对于特殊的或者复杂的需求我们可以使用PlayableAPI,自定义链接,实现3的树结构。

ClipCaps

面板结构如图,我们将其分为6个区域:
在这里插入图片描述
上图中s表示以秒为单位,f表示以帧为单位。

ClipCaps 拥有部分
All 1,2,3,4,5,6
None 1
Looping 1
Extrapolation 1,5
ClipIn 1,3
SpeedMultiplier 1,4
Blending 1,6

在这里插入图片描述
对于ClipAsset只需要实现ITimelineClipAsset接口,返回对应类型即可。真正的数据操作是在TimelineClip中进行。

PlayableDirector

前面说了四大天王,这里终于到了统领将军的时候了。

界面介绍

在这里插入图片描述

  1. Playable我们编辑的Timeline的资源。

  2. UpdateMode
    a.DSP Clock:没用过,说了混音器的时间参数。总之不会用。
    b.GameTime:Unity的Time.DeltaTime(受TimeScale影响)
    c.Unscaled Game Time:Unity中Time.unscaledDeltaTime
    d.Manual:自定义的更新模式,需要我们设置时间,并且调用Evaluate(),大概是这样子:

    playableDirector.time += Time.deltaTime;//我们自定义的时间即可
    playableDirector.Evaluate();
    
  3. PlayOnAwake 是否在Awake时就开始播放。理解为是否在激活时直接播放。

  4. WrapMode 当一次播放完毕后的行为,简称重复模式:
    a. Hold:保持在结束后的最后一帧。
    b. Loop:循环播放,结束后重头再来
    c. None:结束后继续往后走,所以如何播放取决于如果最后一个片段的AnimationExtrapolation(啥?不知道是啥?看上面的ClipCaps啊~)

  5. Initial Time 播放时,跳过的时间。如果上面的WrapMode是Loop则循环时此数据无效。

  6. Bindings 每个轨道的名称,绑定的物体(其实就是输出给谁)

常用函数

功能 函数名 备注
开始 Play() 还有两个重载,回调 Action<PlayableDirector> played
暂停 Pause() 回调Action<PlayableDirector> paused
继续 Resume()
停止 Stop() 回调Action<PlayableDirector> stopped
评估 Evaluate() 自定义UpdateMode使用
延迟评估 DeferredEvaluate() 在下一帧生效
设置Binding SetGenericBinding(Object key, Object value)
获取Binding Object GetGenericBinding(Object key)
清除Binding ClearGenericBinding(Object key)
设置引用数据 SetReferenceValue(PropertyName id, Object value)
获取引用数据 Object GetReferenceValue(PropertyName id, out bool idValid)
清除引用数据 ClearReferenceValue(PropertyName id)
Graph playableGraph { get; }
PlayableAsset playableAsset { get; set; }
重构Graph RebuildGraph()
重构输出 RebindPlayableGraphOutputs() 设置或更改binding后调用下。

结束语

想对TimeLine的结构做个分析,有时间在做吧。

猜你喜欢

转载自blog.csdn.net/u010778229/article/details/116197934