草庐IT

【Unity】认识常用的生命周期函数(Awake、Start、Update...)

_ElecSheep 2024-04-07 原文

一、了解帧的概念

游戏的本质就是一个死循环
每一次循环都会处理游戏逻辑 并 更新一次游戏画面
之所以能看到画面在动 是因为
切换画面速度达到一定速度时
人眼就会认为画面是动态且流畅的
一帧就是执行了一次循环
Unity底层已经封装好了这个死循环
我们只需要利用Unity的生命周期函数的规则来执行游戏逻辑即可

FPS(Frames Per Second)
即每秒钟帧数
一般我们说60帧30帧
意思是1秒更新60次、30次画面
1s = 1000ms
60帧:1帧为 1000ms/60 ≈ 16.66ms
30帧:1帧为 1000ms/30 ≈ 33.33ms

游戏卡顿的原因:
跑1帧游戏逻辑的计算量过大,或者硬件性能过低,无法在一帧的时间内处理完所有游戏逻辑

二、生命周期函数的概念

所有继承MonoBehavior的脚本 最终都会挂载到GameObject游戏对象上
生命周期函数就是该脚本对象依附的GameObject对象从出生到消亡整个生命周期中
会通过反射自动调用的一些特殊函数

Unity帮助我们记录了一个GameObject对象依附了哪些脚本
会自动地得到这些对象,通过反射去执行一些固定名字的函数(就是生命周期函数)

三、生命周期函数

注意:
生命周期函数的访问修饰符一般为private和protected
因为不需要在外部手动调用生命周期函数,都是Unity自动帮我们调用

3-1.Awake

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
    //当一个对象(自己这个类对象 而不是依附的GameObject)被创建时,会调用该生命周期函数
    //作用:Awake是类似构造函数的存在,我们可以在一个类对象刚被创建时,进行一些初始化操作
    //Awake只会被执行一次
    private void Awake()
    {
        //补充知识点:在Unity中打印信息的两种方式
        //1.如果没有继承MonoBehaviour,可以使用debug.Log();
        Debug.Log("我是打印的信息");
        Debug.LogWarning("警告!");
        Debug.LogError("出错了!");

        //2.如果继承了MonoBehaviour 有一个现成的方法可以实现打印
        print("我是打印的信息");
    }
}

3-2.OnEnable

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
    //依附的GameObject对象每次被激活时 会被调用
    //作用:想要当一个对象被激活时 进行一些逻辑处理,就可以写在本函数中
    private void OnEnable()
    {
        print("我依附的GameObject被激活了");
    }
}

3-2.Start

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
    //从自己被创建出来后,第一次帧更新之前被调用
    //作用:还是用于初始化信息的,但是它相对Awake来说,要执行的晚一些
    //      因为它是在对象进行帧更新之前才会被执行
    //一个对象只会调用一次
    private void Start()
    {
        print("我在第1帧更新前被执行");
    }
}

3-4.FixedUpdate

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
    //固定间隔时间执行,间隔的时间可以设置
    //作用:用于进行物理相关的更新(如碰撞检测)
    //      它是每一帧都会执行的,但是这里的帧和游戏帧有点不同
    private void FixedUpdate()
    {
        print("我会固定间隔时间循环执行");
    }
}


3-5.Update

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
    //逻辑帧更新
    //每秒更新多少次是可以设置的,如果不设置 默认会以最快的速度更新
    //作用:用于处理游戏核心逻辑更新
    private void Update()
    {
        print("我一帧被执行一次");
    }
}

3-6.LateUpdate

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
    //每帧执行 于Update之后执行
    //作用:一般用来处理摄像机位置更新相关内容
    //      在Update和LateUpdate之间,Unity进行了一些处理,处理动画相关的更新
    private void LateUpdate()
    {
        print("我每针都会被执行,但晚于Update");
    }
}

3-7.OnDisable

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
    //依附的GameObject对象每次失活时被调用(对象被销毁时也会被调用)
    //作用:想要当一个对象失活时 进行一些逻辑处理,就可以写在本函数中
    private void OnDisable()
    {
        print("我依附的GameObject失活了");
    }
}

3-8.OnDestroy

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
    //对象被销毁时被调用(依附的GameObject对象被删除时)
    private void OnDestroy()
    {
        print("我被销毁了");
    }
}

四、生命周期函数支持继承和多态


Lesson1的脚本如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
    //把Awake写成一个虚函数
    protected virtual void Awake()
    {
        print("父类的Awake");
    }
}

Lesson1Son的脚本如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1Son : Lesson1
{
    //可以重写父类Lesson1的虚函数
    protected override void Awake()
    {
        base.Awake();
        print("子类的Awake");
    }
}

运行:可以看到,父类的Awake和子类的Awake都被执行了,所以生命周期函数支持继承和多态

五、补充:关于继承Mono的类的构造函数

要知道,虽然不建议在继承MonoBehavior的类中写构造函数
但是不意味着不能写,当在继承MonoBehavior的类中写无参构造函数时
会发现在编辑模式下或者运行后,只要该脚本挂载在场景中,那么该无参构造函数是会被自动执行
因为Unity的工作原理中提到的反射机制,实际上Unity通过反射帮助我们实例化了该脚本对象
既然要实例化那么肯定是需要new的,只不过Unity中不需要我们自己new继承了MonoBehavior的类,只要挂载后Unity就帮助我们做了这件事

那么为什么不建议继承MonoBehavior的类写构造函数呢?
1.Unity的规则就是,继承MonoBehavior的脚本不能new只能挂载
2.生命周期函数的Awake是类似构造函数的存在,当对象出生就会自动调用
3.写构造函数反而在结构上会破坏Unity设计上的规范
总结:
如果继承MonoBehavior的脚本想要进行初始化相关,可以在Awake或者Start中进行,搞清这两个生命周期函数的执行时机,根据需求选择在哪里进行初始化。
切记!!继承MonoBehavior的脚本不要new,不要new,不要new!!

六、补充:不同对象的声明周期函数是在同一个线程中执行的吗?

Unity中所有对象上挂载的生命周期函数都是在一个主线程中按先后执行的
Unity会主动把场景上的对象,对象上挂载的脚本都统统记录下来,
在主线程的死循环中,按顺序按时机的通过反射,执行记录的对象身上挂载的脚本的对应生命周期函数

有关【Unity】认识常用的生命周期函数(Awake、Start、Update...)的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  3. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  4. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  5. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  6. unity---接入Admob - 2

    目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里​编辑 3.解析依赖到项目中

  7. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  8. ruby-on-rails - 在 Rails 3 中进行身份验证最常用的方法是什么? - 2

    我需要在rail3中使用标准注册/登录/忘记密码功能进行身份验证。是否有大多数人为此使用的插件或其他东西? 最佳答案 我不确定最常用的方法是什么-但可以肯定的是,Plataformatec的“Devise”是一个非常流行的方法:http://github.com/plataformatec/devise我已经尝试了一些authgem,对我来说,它是最简单的设置和修改以满足我的需要。它内置了密码恢复、帐户确认(如果需要)和其他一些非常方便的功能。 关于ruby-on-rails-在Rail

  9. ruby-on-rails - 如何在 Rails 中添加禁用的提交按钮 - 2

    我在ruby​​表单中有一个提交按钮f.submitbtn_text,class:"btnbtn-onemgt12mgb12",id:"btn_id"我想在不使用任何javascript的情况下通过ruby​​禁用此按钮 最佳答案 添加disabled:true选项。f.submitbtn_text,class:"btnbtn-onemgt12mgb12",id:"btn_id",disabled:true 关于ruby-on-rails-如何在Rails中添加禁用的提交按钮,我们在St

  10. ruby - 如何保持我不常用的编程语言技能 - 2

    关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby​​-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby​​有很大不同。由于我与ruby​​之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?

随机推荐