微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

在这里插入图片描述

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐