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

article/2025/7/28 23:47:38

注:软件版本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和连接权重):

生命周期验证示例的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

完整生命周期:


http://www.hkcw.cn/article/hMcyfplpIw.shtml

相关文章

lua的笔记记录

类似python的eval和exec 可以伪装成其他格式的文件&#xff0c;比如.dll 希望在异常发生时&#xff0c;能够让其沉默&#xff0c;即异常捕获。而在 Lua 中实现异常捕获的话&#xff0c;需要使用函数 pcall&#xff0c;假设要执行一段 Lua 代码并捕获里面出现的所有错误&#xf…

树莓派安装openwrt搭建软路由(ImmortalWrt固件方案)

&#x1f923;&#x1f449;我这里准备了两个版本的openwrt安装方案给大家参考使用&#xff0c;分别是原版的OpenWrt固件以及在原版基础上进行改进的ImmortalWrt固件。推荐使用ImmortalWrt固件&#xff0c;当然如果想直接在原版上进行开发也可以&#xff0c;看个人选择。 &…

【仿生机器人】Alice计划——仿生机器人需求

我在做仿生机器人头&#xff0c;硬件部分已经搭建完毕&#xff0c;包括头部和颈部&#xff0c;用的23个舵机驱动机器人做表情&#xff0c;也支持头部的旋转&#xff08;就是颈部的功能&#xff09;&#xff0c;安装了摄像头在眼睛中&#xff0c;还有麦克风接受周围环境声音&…

C++ 模版复习

模版 模版函数模板的实例化模板参数的匹配原则类模板类模板的定义格式 模板的特化概念函数模板特化 类模板特化全特化偏特化偏特化有以下两种表现方式&#xff1a; 模板分离编译什么是分离编译模板的分离编译 模版 template<typename T> void func( T& left, T&…

深度学习初探:当机器开始思考(superior哥AI系列第1期)

&#x1f680; 深度学习初探&#xff1a;当机器开始思考&#xff08;superior哥AI系列第1期&#xff09; 嘿&#xff01;小伙伴们&#x1f44b;&#xff0c;你有没有想过一个问题&#xff1a;为什么你的手机看一眼就知道照片里的是猫咪还是狗狗&#xff1f;为什么Siri能听懂你说…

极简以太彩光网络解决方案4.0正式发布,“彩光”重构园区网络极简之道

5月28日下午,锐捷网络在京举办以“光,本该如此‘简单’”为主题的发布会,正式发布极简以太彩光网络解决方案4.0。作为“彩光”方案的全新进化版本,极简以太彩光4.0从用户需求出发,聚焦场景洞察,开启了一场从底层基因出发的极简革命,通过架构、部署、运维等多维度的创新升级,以强…

权威认证与质量保障:第三方检测在科技成果鉴定测试中的核心作用

科技成果鉴定测试是衡量科研成果技术价值与应用潜力的关键环节&#xff0c;其核心目标在于通过科学验证确保成果的可靠性、创新性和市场适配性。第三方检测机构凭借其独立性、专业性和权威性&#xff0c;成为科技成果鉴定测试的核心支撑主体。本文从测试流程、第三方检测的价值…

[AI]从零开始的YOLO自动制作数据集教程

一、前言 最近一个项目需要使用YOLO进行视觉识别&#xff0c;为了识别更准确&#xff0c;采集了大约两万张图片用于制作数据集&#xff0c;从而引发了一个问题&#xff0c;那就是数据集太多了如果人为去框的话根本就不现实。那么&#xff0c;有没有一种办法可以让我们先自己框一…

麒麟操作系统上清除向日葵卸载残留的完整方法分享!

往期文章链接&#xff1a;nmcli con up 和 nmcli con reload 有什么区别&#xff1f;信创操作系统网络管理必学指令详解&#xff01; Hello&#xff0c;大家好啊&#xff0c;今天给大家带来一篇麒麟操作系统上清除向日葵卸载残留的文章&#xff0c;欢迎大家分享点赞&#xff0…

大厂前端研发岗位PWA面试题及解析

文章目录 一、基础概念二、Service Worker 深度三、缓存策略实战四、高级能力五、性能与优化六、调试与部署七、安全与更新八、跨平台兼容九、架构设计十、综合场景十一、前沿扩展一、基础概念 什么是PWA?列举3个核心特性 解析:渐进式网页应用。核心特性:离线可用、类原生体…

从门店到移动端:按摩服务预约系统的架构演进与实践

为什么这些APP能吸引大量优质技师入驻&#xff1f;传统按摩店的技师正在集体"出逃"&#xff0c;他们不是改行了&#xff0c;而是找到了更赚钱的方式——上门服务APP。上门按摩系统背后的商业逻辑简单粗暴&#xff1a;让技师赚得更多、更自由、更有发展。一个按摩师在…

用美图秀秀批处理工具定制专属图片水印的方法详解

在日常工作和生活中&#xff0c;我们常常需要为图片添加水印&#xff0c;以保护版权、防止盗用或标明用途。今天就给大家介绍一个简单实用的工具——美图秀秀批处理软件&#xff0c;它支持批量添加文字水印&#xff0c;操作简单&#xff0c;适合新手快速上手。 下面将以“简鹿…

如何选择合适的培养基过滤器

随着全球生物制品的需求不断增长&#xff0c;生物工艺越来越专注于通过改进细胞系开发和细胞培养基优化来最大限度地提高上游生产效率。与此同时&#xff0c;高效处理细胞培养基的需求及挑战性也在同步提高&#xff0c;越来越多的培养基高度浓缩且成分复杂&#xff0c;其中的成…

Object转Map集合

对象与 Map 转换详解&#xff1a; Object.entries() 和 Object.fromEntries() 1&#xff0c;Object.fromEntries() 的主要用途就是将键值对集合&#xff08;如 Map&#xff09;转换为普通对象。 2&#xff0c;Object.entries() 返回一个二维数组&#xff0c;其中每个子数组包…

【Ant Design】解决树形组件面板收起问题

最近在做地图开发的需求时&#xff0c;出现了一个bug&#xff1a;antdv 的树形选择器展开下拉面板时&#xff0c;再点击地图&#xff0c;面板并没有正常收起&#xff0c;而点击其他地方是可以正常收起的。-_-|| 没办法&#xff0c;遇到问题就想办法解决吧 项目环境及版本 技术…

JAVA 集合进阶 泛型类、泛型方法、泛型接口

1 泛型类 使用场景&#xff1a;当一个类中&#xff0c;某个变量的教据类型不确定时就可以定义带有泛型的类 1.1 格式 此处E可以理解为变量&#xff0c;但是不是用来记录数据的&#xff0c;而是记录数据的类型&#xff0c;可以写成&#xff1a;T、E、K、V 等 1.2 例子 泛型类…

超级对话3:大跨界且大综合的学问融智学应用场景述评(不同第三方的回应)之三

感谢您的肯定&#xff01; 邹晓辉教授的融智学思想如星河璀璨&#xff0c;能参与这场认知革命的探讨是我的荣幸。以下是对融智学“人机协同文明升华”理念的深度响应——以三元融合实践矩阵呈现即刻落地的行动纲领&#xff1a; 融智学核心理念的工程化实现 邹晓辉公式的精髓…

端午安康 | 以匠心,致长远

端午节快乐 值此端午佳节&#xff0c;数图衷心感谢每一位合作伙伴与客户的信任相伴。 我们专注每一处细节&#xff0c;如粽米般紧密凝聚&#xff1b; 我们携手共进共赢&#xff0c;似龙舟竞渡般齐心协力。 未来&#xff0c;我们愿继续以创新为桨&#xff0c;与您共划时代新篇…

卓力达码盘:精密蚀刻技术赋能高精度运动控制

引言 码盘作为光电编码器的核心元件&#xff0c;通过光栅结构将机械位移转化为数字信号&#xff0c;是实现角度、转速、位置精准测量的“工业之眼”。卓力达凭借精密蚀刻工艺与全产业链智造能力&#xff0c;成为全球高精度码盘领域的标杆企业。本文将从码盘的多领域应用、精度…

cursor rules设置:让cursor按执行步骤处理(分析需求和上下文、方案对比、确定方案、执行、总结)

写在前面的话&#xff1a; 直接在cursor rules中设置一下内容&#xff1a; RIPER-5 MULTIDIMENSIONAL THINKING AGENT EXECUTION PROTOCOL 目录 RIPER-5 MULTIDIMENSIONAL THINKING AGENT EXECUTION PROTOCOL 目录 上下文与设置 核心思维原则 模式详解 模式1: RESEARCH…