Monobehavior生命周期一探究竟
前言Monobehavior生命周期函数表网上都有,这里只研究经常遇到的,重点关注FixedUpdate、Update、LateUpdate与OnGUIpublic class MonoLifeTest : MonoBehaviour{private void Awake() // 最先调用,只调用一次,只依赖于脚本所附属的物体,与脚本的激活状态无关,也就是说只要所属物体是激活的,无论脚本是否处于
前言
Monobehavior生命周期函数表网上都有,这里只研究经常遇到的,重点关注FixedUpdate、Update、LateUpdate与OnGUI
public class MonoLifeTest : MonoBehaviour
{
private void Awake() // 最先调用,只调用一次,只依赖于脚本所附属的物体,与脚本的激活状态无关,也就是说只要所属物体是激活的,无论脚本是否处于激活状态都会调用
{
Debug.LogError("Awake");
}
private void OnEnable() // 脚本或脚本附属的物体被激活时调用,重复改变状态重复调用
{
Debug.LogError("OnEnable");
}
private void Start() // Update之前调用,只调用一次
{
Debug.LogError("Start");
}
private void FixedUpdate() // 固定时间间隔调用,在update之前,循环调用多次,适合处理一些物理逻辑,但不要滥用
{
Debug.LogError("FixedUpdate");
}
private void Update() // 每渲染帧调用一次,与设备的性能以及渲染的物体有关,也就是说不同性能的设备的调用间隔不同,所以导致了相同的游戏在不同的设备上的表现不同
{
Debug.LogError("Update");
}
private void LateUpdate() // 在Update调用之后调用,调用多次,可用于摄像机跟随
{
Debug.LogError("LateUpdate");
}
private void OnGUI() // 在Update与LateUpdate之后调用,每帧调用多次,用于渲染和处理GUI事件,同其它函数一样在脚本处于非激活状态时不执行
{
Debug.LogError("OnGUI");
}
private void OnDisable() // 在取消脚本激活状态时调用一次
{
Debug.LogError("OnDisable");
}
private void OnDestroy() // 销毁脚本及脚本所属物体时调用一次,同Awake的地方在于只要脚本所属物体是处于激活状态,即使脚本属于非激活状态,销毁时也会调用
{
Debug.LogError("OnDestroy");
}
}
Awake与OnDestroy
1.我们将脚本设为非激活状态,将脚本所属物体设为激活状态
运行游戏
删除物体
或者删除脚本
可以发现只要脚本所属物体处于激活状态,无论脚本是否处于激活状态都会执行里面的Awake与OnDestroy方法,其它方法不执行
2. 我们将脚本处于激活状态,脚本所属物体处于非激活状态
运行游戏
发现所有函数都没有输出,那是因为物体(载体)没有激活
我很好奇此时MonoLifeTest的实际激活状态,所以我调整了一下结构将Directional Light设为Main Camera的父物体(否则采用GameObject.Find找不到隐藏物体),并写了一个辅助脚本FindScriptTest挂在Directional Light上如图
public class FindScriptTest : MonoBehaviour
{
void Start()
{
//GameObject monoLifeTestGo = GameObject.Find("Main Camera");
//GameObject monoLifeTestGo = GameObject.FindGameObjectWithTag("MainCamera");
GameObject monoLifeTestGo = transform.Find("Main Camera").gameObject;
if (monoLifeTestGo != null)
{
Debug.LogError("找到了Main Camera");
MonoLifeTest script = monoLifeTestGo.GetComponent<MonoLifeTest>();
if (script != null)
{
Debug.LogError("找到了MonoLifeTest");
Debug.LogError("MonoLifeTest脚本的状态:" + script.enabled);
}
}
else
{
Debug.LogError("没找到Main Camera");
}
}
}
运行游戏
可以看到MonoLifeTest脚本本身确实是激活状态
3. 总结:Awake与OnDestroy的调用仅受脚本所属物体的激活状态控制,而其它函数则需要脚本和所属物体都处于激活状态才会调用
OnGUI
官方解释:OnGUI在渲染和处理GUI事件时调用,可能会在每个渲染帧中调用多次
OnGUI is called for rendering and handling GUI events. This means that your OnGUI implementation might be called several times per frame (one call per event).
另外,当移动鼠标到Game视图区域,或者改变Game视图的大小时OnGUI仍会调用,不会因为游戏处于暂停状态而终止,其它每帧调用的函数却不会,测试OnDisable与OnDestroy也会
Time.deltaTime
官方解释:完成上一帧所消耗的秒数,只读
The time in seconds it took to complete the last frame (Read Only).
private void FixedUpdate()
{
Debug.LogError("FixedUpdate:" + Time.deltaTime.ToString());
}
private void Update()
{
Debug.LogError("Update:" + Time.deltaTime.ToString());
}
private void LateUpdate()
{
Debug.LogError("LateUpdate:" + Time.deltaTime.ToString());
}
private void OnGUI()
{
Debug.LogError("OnGUI:" + Time.deltaTime.ToString());
}
可以看出Update、LateUpdate与OnGUI共用一个时间增量即渲染帧增量,FixedUpdate自己用一个时间增量即固定帧增量,可在Edit->Project Settings->Time->Fixed Timestep中修改
FixedUpdate的调用间隔
那么FixedUpdate的调用间隔真的是恰好的0.02s吗?
private float m_LastTime;
private float m_NowTime;
private float m_Offset;
private void FixedUpdate()
{
m_NowTime = Time.realtimeSinceStartup;
m_Offset = m_NowTime - m_LastTime;
m_LastTime = m_NowTime;
Debug.LogError("FixedUpdate:" + m_Offset.ToString());
}
可以看出FixedUpdate的调用间隔并非固定的0.02s
总结
- FixedUpdate->Update->LateUpdate->OnGUI
- Awake与OnDestroy的调用仅受脚本所属物体的激活状态控制,而其它函数则需要脚本和所属物体都处于激活状态才会调用
- OnGUI在游戏暂停的状态下也有可能触发
- Time.deltaTime的值分为渲染帧和固定帧,Update、LateUpdate与OnGUI共用一个渲染帧增量,是每帧都在变化的,FixedUpdate自己用一个固定帧增量是固定的一般是0.02s,可手动设置
- FixedUpdate的调用间隔实际上并非是固定的
更多推荐
所有评论(0)