> 技术文档 > 【Unity博客节选】PlayableGraph 的生命周期

【Unity博客节选】PlayableGraph 的生命周期


注:软件版本Unity 6.0 + Timeline 1.8.7

作者:CSDN @ RingleaderWang
原文:《Unity第25期——Timeline结构及其源码浅析》
文章首发Github👍:《Timeline结构及其源码浅析》

Bilibili 视频版👍👍:《Timeline结构及其源码解析》https://www.bilibili.com/video/BV1bHjYzNE35

PlayableGraph 的生命周期

原文运行时多次提到了 PrepareFrame、ProcessFrame,其实这就是ScriptPlayable在某段生命周期执行的回调函数,我们可以利用 ScriptPlayable 传入自定义PlayableBehaviour 来干涉Playable的生命周期。

Playable的生命周期有:

  • GraphStart:graph play 开始时
  • GraphStop:graph stop时
  • PlayableCreate:Playable Create时
  • PlayableDestroy:Playable Destroy时
  • BehaviourPlay:Playable 运行时
  • BehaviourPause:Playable 暂停时
  • PrepareFrame:每帧处理数据前
  • ProcessFrame:每帧开始处理数据时

当然可能并非都是这些生命周期,比如AnimationScriptPlayable就有个ProcessAnimationProcessRootMotion过程,可能就没有所谓的ProcessFrame了。

当然对于ScriptPlayable,上面的生命周期是确定的,在Playable处于上面的生命周期时,便会执行对应的回调函数(注册在PlayableBehaviour里)。

下面的自定义PlayableBehaviour就是简单打印回调方法和playable:

public class TimelineTestForAnimationScriptBehaviour : PlayableBehaviour { public override void OnGraphStart(Playable playable) { DebugLog(playable,\"OnGraphStart\"); } private static void DebugLog(Playable playable, string methodName) { Debug.Log($\"Playable by in/output cnt_{playable.GetInputCount()}{playable.GetOutputCount()} Behaviour:{methodName}\"); } public override void OnGraphStop(Playable playable) { DebugLog(playable,\"OnGraphStop\"); } public override void OnPlayableCreate(Playable playable) { DebugLog(playable,\"OnPlayableCreate\"); } public override void OnPlayableDestroy(Playable playable) { DebugLog(playable,\"OnPlayableDestroy\"); } public override void OnBehaviourPlay(Playable playable, FrameData info) { DebugLog(playable,\"OnBehaviourPlay\"); } public override void OnBehaviourPause(Playable playable, FrameData info) { DebugLog(playable,\"OnBehaviourPause\"); } public override void PrepareFrame(Playable playable, FrameData info) { DebugLog(playable,\"PrepareFrame\"); }  public override void ProcessFrame(Playable playable, FrameData info, object playerData) { DebugLog(playable,\"ProcessFrame\"); } }

生命周期验证

上面生命周期的理解还比较模糊,尤其父子节点回调执行顺序是什么需要验证。

验证代码如下(给不同节点设置不同端口数能很方便辨析是哪个节点的回调):

using System;using Scenes.TimelineTest.scripts;using UnityEditor;using UnityEngine;using UnityEngine.Playables;public class TimelineTestForLifeCycle : MonoBehaviour{ public PlayableGraph graph; private ScriptPlayable<TimelineTestForAnimationScriptBehaviour> playable3; public void CreateGraph() { DestroyGraph(); graph = PlayableGraph.Create(\"TimelineTestForLifeCycle\"); ScriptPlayableOutput output = ScriptPlayableOutput.Create(graph,\"LifeCycleTestOutput\"); var playable5 = ScriptPlayable<TimelineTestForAnimationScriptBehaviour>.Create(graph,5); var playable4 = ScriptPlayable<TimelineTestForAnimationScriptBehaviour>.Create(graph,4); playable3 = ScriptPlayable<TimelineTestForAnimationScriptBehaviour>.Create(graph,3); var playable2 = ScriptPlayable<TimelineTestForAnimationScriptBehaviour>.Create(graph,2); var playable1 = ScriptPlayable<TimelineTestForAnimationScriptBehaviour>.Create(graph,1); output.SetSourcePlayable(playable5,0); output.SetWeight(1); playable5.ConnectInput(0,playable1,0,1); playable5.ConnectInput(1,playable2,0,0.5f); playable3.Pause(); playable5.ConnectInput(2,playable3,0,1); playable5.ConnectInput(3,playable4,0,0); var playable9 = ScriptPlayable<TimelineTestForAnimationScriptBehaviour>.Create(graph,9); var playable8 = ScriptPlayable<TimelineTestForAnimationScriptBehaviour>.Create(graph,8); playable9.ConnectInput(0,playable8,0,1); } public void PlayPlayable3() { playable3.Play(); } public void PausePlayable3() { playable3.Pause(); } public void DestroyPlayable3() { playable3.Destroy(); } public void PlayGraph() { graph.Play(); } private void OnDestroy() { DestroyGraph(); } public void DestroyGraph() { if (graph.IsValid()) { Debug.Log(\"Execute Graph Destroy\"); graph.Destroy(); Debug.Log(\"Graph destroyed\"); } }}[CustomEditor(typeof(TimelineTestForLifeCycle))]class TimelineTestForLifeCycleEditor : Editor{ public override void OnInspectorGUI() { base.OnInspectorGUI(); TimelineTestForLifeCycle script = (TimelineTestForLifeCycle) target; if (GUILayout.Button(\"CreateGraph\")) { script.CreateGraph(); } if (GUILayout.Button(\"PlayGraph\")) { script.PlayGraph(); } if (GUILayout.Button(\"Destroy graph\")) { script.DestroyGraph(); } if (GUILayout.Button(\"Play Playable3\")) { script.PlayPlayable3(); } if (GUILayout.Button(\"Pause Playable3\")) { script.PausePlayable3(); } if (GUILayout.Button(\"Destroy Playable3\")) { script.DestroyPlayable3(); } }}

点击 “CreateGraph” 后的 graph 结构(图中标注的是节点设置的play state和连接权重):

【Unity博客节选】PlayableGraph 的生命周期

生命周期验证示例的graph图

当前脚本主要测试graph的 create与play(除了prepareFrame、processFrame),验证:

  • graph不play,playable节点是否会运行
  • 没有playableOutput,playable节点是否会运行
  • 输出权重为0,playable节点是否会运行
  • pause状态,playable节点是否会运行
  • PrepareFrame、ProcessFrame顺序
  • Graph destroy执行效果

【Unity博客节选】PlayableGraph 的生命周期

打印结果:

// 打印Playable by in/output cnt_51 Behaviour:OnPlayableCreate Playable by in/output cnt_41 Behaviour:OnPlayableCreate Playable by in/output cnt_31 Behaviour:OnPlayableCreate Playable by in/output cnt_21 Behaviour:OnPlayableCreate Playable by in/output cnt_11 Behaviour:OnPlayableCreate Playable by in/output cnt_91 Behaviour:OnPlayableCreate Playable by in/output cnt_81 Behaviour:OnPlayableCreate Playable by in/output cnt_51 Behaviour:OnGraphStart Playable by in/output cnt_51 Behaviour:OnBehaviourPlay Playable by in/output cnt_11 Behaviour:OnGraphStart Playable by in/output cnt_11 Behaviour:OnBehaviourPlay Playable by in/output cnt_21 Behaviour:OnGraphStart Playable by in/output cnt_21 Behaviour:OnBehaviourPlay Playable by in/output cnt_31 Behaviour:OnGraphStart Playable by in/output cnt_31 Behaviour:OnBehaviourPause Playable by in/output cnt_41 Behaviour:OnGraphStart Playable by in/output cnt_41 Behaviour:OnBehaviourPlay Playable by in/output cnt_51 Behaviour:PrepareFrame Playable by in/output cnt_11 Behaviour:PrepareFrame Playable by in/output cnt_21 Behaviour:PrepareFrame Playable by in/output cnt_41 Behaviour:PrepareFrame Playable by in/output cnt_11 Behaviour:ProcessFrame Playable by in/output cnt_21 Behaviour:ProcessFrame Playable by in/output cnt_41 Behaviour:ProcessFrame Playable by in/output cnt_51 Behaviour:ProcessFrame Graph destroyed Playable by in/output cnt_51 Behaviour:OnBehaviourPause Playable by in/output cnt_11 Behaviour:OnBehaviourPause Playable by in/output cnt_21 Behaviour:OnBehaviourPause Playable by in/output cnt_41 Behaviour:OnBehaviourPause Playable by in/output cnt_51 Behaviour:OnGraphStop Playable by in/output cnt_51 Behaviour:OnPlayableDestroy Playable by in/output cnt_41 Behaviour:OnGraphStop Playable by in/output cnt_41 Behaviour:OnPlayableDestroy Playable by in/output cnt_31 Behaviour:OnGraphStop Playable by in/output cnt_31 Behaviour:OnPlayableDestroy Playable by in/output cnt_21 Behaviour:OnGraphStop Playable by in/output cnt_21 Behaviour:OnPlayableDestroy Playable by in/output cnt_11 Behaviour:OnGraphStop Playable by in/output cnt_11 Behaviour:OnPlayableDestroy Playable by in/output cnt_91 Behaviour:OnPlayableDestroy Playable by in/output cnt_81 Behaviour:OnPlayableDestroy

结合Graph Monitor 可以得出结论:

  • graph不play,playable节点不会运行
  • 没有连ScriptPlayableOutput,ScriptPlayable节点不会运行(playable time不随时间增加),且除了OnPlayableCreate和OnPlayableDestroy,其他回调方法不会触发
  • 输出权重为0,playable节点依然运行
  • pause状态,playable节点不会运行
  • graph未play,playable执行pause并不会触发OnBehaviourPause
  • graph 执行Play() 后:若playable是playing状态时,则触发OnBehaviourPlay回调;是paused状态时,则触发OnBehaviourPause回调
  • 会以前序遍历(父节点优先)的方式触发OnGraphStart 和 OnBehaviourPlay/Pause
  • 会以前序遍历(父节点优先)的方式触发PrepareFrame回调
  • 会以后序遍历(子节点优先)的方式触发ProcessFrame回调
  • 没有连接playableOutput的playable节点不会触发OnGraphStart/OnGraphStop回调
  • 直接Destroy graph时,如果graph未stop会先触发OnBehaviourPause、OnGraphStop回调,这两个回调的触发逻辑与先Stop Graph后Destroy Graph 略有不同,如下日志:
// 先Stop graph 再 Destroy graph的日志(与直接Destroy graph有差异)graph.Stop()Playable by in/output cnt_51 Behaviour:OnBehaviourPause Playable by in/output cnt_51 Behaviour:OnGraphStop Playable by in/output cnt_11 Behaviour:OnBehaviourPause Playable by in/output cnt_11 Behaviour:OnGraphStop Playable by in/output cnt_21 Behaviour:OnBehaviourPause Playable by in/output cnt_21 Behaviour:OnGraphStop Playable by in/output cnt_31 Behaviour:OnBehaviourPause Playable by in/output cnt_31 Behaviour:OnGraphStop Playable by in/output cnt_41 Behaviour:OnBehaviourPause Playable by in/output cnt_41 Behaviour:OnGraphStop Graph.Destroy() Playable by in/output cnt_51 Behaviour:OnPlayableDestroy Playable by in/output cnt_41 Behaviour:OnPlayableDestroy Playable by in/output cnt_31 Behaviour:OnPlayableDestroy Playable by in/output cnt_21 Behaviour:OnPlayableDestroy Playable by in/output cnt_11 Behaviour:OnPlayableDestroy Playable by in/output cnt_91 Behaviour:OnPlayableDestroy Playable by in/output cnt_81 Behaviour:OnPlayableDestroy

完整生命周期:
【Unity博客节选】PlayableGraph 的生命周期