【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
就有个ProcessAnimation
和ProcessRootMotion
过程,可能就没有所谓的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和连接权重):
生命周期验证示例的graph图
当前脚本主要测试graph的 create与play(除了prepareFrame、processFrame),验证:
- graph不play,playable节点是否会运行
- 没有playableOutput,playable节点是否会运行
- 输出权重为0,playable节点是否会运行
- pause状态,playable节点是否会运行
- PrepareFrame、ProcessFrame顺序
- Graph destroy执行效果
打印结果:
// 打印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
完整生命周期: