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

一、了解帧的概念

游戏的本质就是一个死循环
每一次循环都会处理游戏逻辑 并 更新一次游戏画面
之所以能看到画面在动 是因为
切换画面速度达到一定速度时
人眼就会认为画面是动态且流畅的
一帧就是执行了一次循环
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自动帮我们调用
image

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被激活了");
    }
}

image

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("我会固定间隔时间循环执行");
    }
}

image
image

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失活了");
    }
}

image

3-8.OnDestroy

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

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

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

image
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");
    }
}

image

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

五、补充:关于继承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会主动把场景上的对象,对象上挂载的脚本都统统记录下来,
在主线程的死循环中,按顺序按时机的通过反射,执行记录的对象身上挂载的脚本的对应生命周期函数

  • 27
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Unity生命周期函数是在继承MonoBehaviour类后才能使用的一些系统定义好的函数。这些函数会在游戏运行过程中自动被系统调用,而且调用顺序与在代码中的书写顺序无关。常用生命周期函数包括: 1. Awake(): 当脚本实例被加载时调用,用于初始化脚本的变量和引用。 2. Start(): 在Awake()之后调用,用于初始化游戏对象的状态和设置。 3. Update(): 在每一帧更新时调用,用于实现各种游戏行为,例如移动、旋转等。 4. LateUpdate(): 在所有Update()函数执行完后调用,用于处理一些需要在Update()之后进行的操作。 5. FixedUpdate(): 固定时间间隔执行的更新函数,主要用于处理物理模拟和刚体运动等。 6. OnEnable()/OnDisable(): 当游戏对象被启用或禁用时调用,用于处理相关的逻辑。 7. OnDestroy(): 游戏对象被销毁时调用,用于释放资源和清理相关的数据。 8. OnBecameVisible()/OnBecameInvisible(): 当对象对于相机可见或不可见时调用,用于处理对象在可见性变化时的逻辑。 除了以上列出的常用函数外,还存在其他一些特殊用途的生命周期函数,例如OnTriggerEnter()/OnTriggerExit()用于处理碰撞逻辑,OnGUI()用于绘制GUI等。通过合理使用这些生命周期函数,可以在Unity中实现各种复杂的游戏行为和逻辑。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Unity学习之生命周期函数](https://blog.csdn.net/weixin_43268649/article/details/120943472)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值