#前言
那什么,有点尴尬。我刚刚才发现上一篇文章的命名错了,上一篇不是扩展阅读而是正篇。居然没有检查标题,我裂开来。
这次我们来讲讲Unity特有的东西,Unity的生命周期!(使用生命周期需要创建的类继承 MonoBehaviour,在Unity创建的代码自动继承这个类。)官方的手册上有详细的描写。
因为官方的解释已经很完整了,所以这篇文章更多的是在搬运内容。
#正文
#简化版生命周期
简化版生命周期适用于新人,里面的每一个事件函数都是生命周期中最为常用的,所有用unity的人都应该背下顺序以及每一个事件函数的调用时机。
下面先来介绍一下每个事件函数的调用时机。
Awake:
始终在任何 Start 函数之前并在实例化预制件之后调用此函数。(如果游戏对象在启动期间处于非活动状态,则在激活之后才会调用 Awake。)Awake的使用中主要考虑的是Awake会在Start之前运行这一特点。常在这个函数里进行一些字段初始化之类的操作。
OnEnable:
(仅在对象处于激活状态时调用)在启用对象后立即调用此函数。在创建 MonoBehaviour 实例时(例如加载关卡或实例化具有脚本组件的游戏对象时)会执行此调用。
Start:
仅当启用脚本实例后,才会在第一次帧更新之前调用 Start。需要在物体被创建时进行的操作,一般都写在这里。
FixedUpdate:
调用 FixedUpdate 的频度常常超过 Update。如果帧率很低,可以每帧调用该函数多次;如果帧率很高,可能在帧之间完全不调用该函数。在 FixedUpdate 之后将立即进行所有物理计算和更新。在 FixedUpdate 内应用运动计算时,无需将值乘以 Time.deltaTime。这是因为 FixedUpdate 的调用基于可靠的计时器(独立于帧率)。FixedUpdate固定时间调用一次,一般可以用来放一些和物理效果有关的代码。比如FPS游戏的子弹射速之类的,如果你用Update每帧去调用射速,就会出现,正常玩家的子弹是正常射速,延迟玩家直接咋瓦鲁多!(我说的是直接在Update写移动,不使用Time.deltaTime调用每帧时间来计算。)
Update:
每帧调用一次 Update。这是用于帧更新的主要函数。
LateUpdate:
每帧调用一次 LateUpdate(在 Update完成后)。LateUpdate 开始时,在 Update 中执行的所有计算便已完成。LateUpdate 的常见用途是跟随第三人称摄像机。如果在 Update 内让角色移动和转向,可以在 LateUpdate 中执行所有摄像机移动和旋转计算。这样可以确保角色在摄像机跟踪其位置之前已完全移动。
OnDisable:
行为被禁用或处于非活动状态时,调用此函数。与OnEnable对应的事件函数,一个是开启(代码),一个是关闭(代码)。
OnDestroy:
对象存在的最后一帧完成所有帧更新之后,调用此函数(可能应 Object.Destroy 要求或在场景关闭时销毁该对象)。当调用GameObject.Destroy(GameObject gameobject)销毁物体时,被销毁的物体就会调用OnDestroy。
以上就是对简化版的生命周期的概述了,对于大部分人来说,这上面的流程可以说是和九九乘法表一样烂熟于心,过于小意思。(如果你觉得挺难记的……那就多看几遍,抄几遍,抄几十遍,直到可以倒着背为止。)
难点的在于整体的生命周期,整体的函数量不少,而且大多平时不怎么用得上,但因为其生命周期的重要地位,至少应该去了解一下。
#生命周期完整版
(这是网图,让我们感谢某位不知名的大佬制作的中文版注释(官方为英文))
里面有好多我也没有使用过。
Reset:
调用 Reset 可以在脚本首次附加到对象时以及使用
Reset
命令时初始化脚本的属性。
以下为生命周期中动画
更新循环更新
的事件函数:
OnStateMachineEnter:
在状态机更新 (State Machine Update) 步骤中,当控制器的状态机进行流经 Entry 状态的转换时,将在第一个更新帧上调用此回调。在转换到 StateMachine 子状态时不会调用此回调。仅当动画图中存在控制器组件(例如,AnimatorController、AnimatorOverrideController 或 AnimatorControllerPlayable 时才会发生此回调。 注意:将此回调添加到 StateMachineBehaviour 组件会禁用多线程的状态机评估。
OnStateMachineExit:
在状态机更新 (State Machine Update) 步骤中,当控制器的状态机进行流经 Exit 状态的转换时,将在最后一个更新帧上调用此回调。在转换到 StateMachine 子状态时不会调用此回调。仅当动画图中存在控制器组件(例如,AnimatorController 、 AnimatorOverrideController 或 AnimatorControllerPlayable 时才会发生此回调。 注意:将此回调添加到 StateMachineBehaviour 组件会禁用多线程的状态机评估。
触发动画事件 (Fire Animation Events):
调用在上次更新时间和当前更新时间之间采样的所有剪辑中的所有动画事件。
StateMachineBehaviour (OnStateEnter/OnStateUpdate/OnStateExit):
一个层最多可以有 3 个活动状态:当前状态、中断状态和下一个状态。使用一个定义 OnStateEnter、OnStateUpdate 或 OnStateExit 回调的 StateMachineBehaviour 组件为每个活动状态调用此函数。依次针对当前状态、中断状态和下一个状态调用此函数。仅当动画图中存在控制器组件(例如,AnimatorController 、AnimatorOverrideController 时才会执行此步骤。
OnAnimatorMove:
在每个更新帧中为每个 Animator 组件调用一次此函数来修改根运动 (Root Motion)。
StateMachineBehaviour(OnStateMove):
使用定义此回调的 StateMachineBehaviour 在每个活动状态中调用此函数。
OnAnimatorIK:
设置动画 IK。为每个启用 IK pass 的 Animator Controller 层进行一次此调用。仅当使用人形骨架时才会执行此事件。
StateMachineBehaviour(OnStateIK):
使用在启用 IK pass 的层上定义此回调的 StateMachineBehaviour 组件在每个活动状态中调用此函数。
WriteProperties:
从主线程将所有其他动画属性写入场景。
下面两个是与刚体和碰撞体有关的事件函数:
OnTriggerXXX(OnTriggerEnter/OnTriggerExit/OnTriggerStay……):
举例的几个函数都关于是3D碰撞的,也有2D的。三个方法分别代表碰撞(进入)时,碰撞(进入)结束时,碰撞(进入)中(或许用触发更妥当吧)。至于需要两个物体都有碰撞体,至少一个物体有刚体,其中一个物体要勾选istrigger这些,我们以后提到的时候再讲吧。
OnCollisionXXX(OnCollisionEnter/OnCollisionExit/OnCollisionStay……):
这个函数是在3D碰撞的开始,结束,碰撞中时调用。
yield是协程的内容,几个事件函数就放在一起讲了:
yield:
在下一帧上调用所有 Update 函数后,协程将继续。
yield WaitForSeconds:
在为帧调用所有 Update 函数后,在指定的时间延迟后继续。
yield WaitForFixedUpdate:
在所有脚本上调用所有 FixedUpdate 后继续。如果协同程序在 FixedUpdate 之前生成,那么它会在当前帧的 FixedUpdate 之后继续运行。
yield WWW:
在 WWW 下载完成后继续。
yield StartCoroutine:
将协程链接起来,并会等待 MyFunc 协程先完成。
OnMouseXXX是用于鼠标与物体的互动:
OnMouseXXX(OnMouseDown/OnMouseDrag/OnMouseEnter……):
这几个函数分别表示鼠标按下,鼠标按下后拖动,鼠标进入,其他的还有鼠标离开,鼠标在物体上,鼠标按下后松开时。OnMouseXXX是通过射线检测来进行判断的,需要物体上有碰撞体。在鼠标经过有碰撞体的物体时,物体上绑定的代码就会执行OnMouseXXX。
接下来的是有关画面渲染方面的事件函数:
OnPreCull:
在摄像机剔除场景之前调用。剔除操作将确定摄像机可以看到哪些对象。正好在进行剔除之前调用OnPreCull。
OnBecameVisible/OnBecameInvisible:
对象变为对任何摄像机可见/不可见时调用。这个看上去还是挺有用的。
OnWillRenderObject:
如果对象可见,则为每个摄像机调用
一次
。
OnPreRender:
在摄像机开始渲染场景之前调用。
OnRenderObject:
所有常规场景渲染完成之后调用。此时,可以使用 GL 类或 Graphics.DrawMeshNow 来绘制自定义几何形状。
OnPostRender:
在摄像机完成场景渲染后调用。
OnRenderImage:
在场景渲染完成后调用以允许对图像进行后处理。这个函数在学shader中的屏幕后处理效果的时候,还是经常用到的。
OnGUI:
每帧调用多次以响应 GUI 事件。首先处理布局和重新绘制事件,然后为每个输入事件处理布局和键盘/鼠标事件。远古时代还是要学的,但现在有了UGUI会的人就少了,但好像写起来很快很方便,我前辈偶尔拿OnGUI写一些简单的提示界面。
OnDrawGizmos:
用于在场景视图中绘制辅助图标以实现可视化。
最后还剩下两个:
OnApplicationPause:
在帧的结尾处调用此函数(在正常帧更新之间有效检测到暂停)。在调用 OnApplicationPause 之后,将发出一个额外帧,从而允许游戏显示图形来指示暂停状态。
OnApplicationQuit:
在退出应用程序之前在所有游戏对象上调用此函数。在编辑器中,用户停止播放模式时,调用函数。
以上就是完整版的Unity生命周期了,其实中间大部分的内容都是直接复制的官方手册中的内容。
Unity生命周期还是需要尽量熟悉的,比起你见到之后去查,直接记忆在脑中要省时间些。
#结束语
-
杂谈
这次就不给大家留题了,你们已经是成熟的程序员了,应该学会自己找题。
这次讲的内容不多(才写了两小时不到,过于轻松了属于是。),但很重要,Unity的生命周期是真的入门用到入土的。不过单看上面的内容确实难以理解,毕竟很多连使用场景都没有讲清楚。所以这次的主要任务是记住简化版的生命周期。其他的东西,就留下一个印象,在未来不断的学习中,它们会逐渐跳入我们的视野中,到时候在回来看看也不迟。
这次的文章就到此为止了,谢谢大家的观看。
本文详细介绍了Unity中MonoBehaviour的生命周期,包括简化版和完整版的生命周期函数,如Awake、Start、Update、LateUpdate等,并阐述了它们的调用时机和应用场景,帮助开发者更好地理解和记忆Unity对象的生命周期。
762

被折叠的 条评论
为什么被折叠?



