【Unity学习日记01】Unity的生命周期

这篇具有很好参考价值的文章主要介绍了【Unity学习日记01】Unity的生命周期。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

参考:Unity官方手册以及Unity生命周期

0 前言

Unity的生命周期指的是Unity脚本从唤醒到销毁的过程,在这个过程里,Unity脚本会按预定顺序执行大量事件函数。

这些函数全部都是系统定义好的,需要继承MonoBehaviour类才能调用。脚本需要挂在任意游戏对象上,并且一个游戏对象可以挂载不同的脚本,各个脚本执行自己的生命周期。

本文将介绍这些事件函数,并说明它们的执行顺序。

1 Unity生命周期图

见官方手册:脚本生命周期流程图

2 Unity生命周期

2.1 初始化阶段

unity生命周期,unity,游戏引擎

1 加载第一个场景

场景开始时将调用以下函数:

Awake
调用时间:当一个脚本实例被载入时,即场景加载时或实例化预制体时,Awake被调用,仅调用一次。
调用条件
游戏对象处于激活状态(如果游戏对象在启动期间处于非激活状态,则在激活之后才会调用Awake。
基于这个调用条件,我们发现,Awake函数执行时并不保证所有对象都已经被加载和初始化,因此不能在其中进行与对象初始化相关的操作,例如在Awake函数中寻找其他对象或设置依赖其他对象的属性,这些操作应该放在Start函数中进行。

OnEnable
调用时间:当对象每次变为可用[1]或激活[2]状态时此函数被调用,可多次调用。
调用条件:游戏对象处于激活状态;游戏脚本处于启用状态。

注释:
可用:对象是否处于场景中。如果对象处于可用状态,则它存在于场景中并且可以被访问。可以使用gameObject.activeSelf属性来检查对象是否处于可用状态。(对象突然可用的情况:在游戏运行时被实例化。
激活:对象是否处于启用状态。当对象处于启用状态时,它将被渲染并响应输入事件。可以使用SetActive()函数来启用或禁用对象。

2 Editor

编辑器模式下才会被调用的函数:

Reset
调用时间:在用户点击检视面板的Reset按钮或者首次添加该组件时被调用。

OnValidate
调用时间:每当设置脚本的属性时都会调用,包括反序列化对象时,这可能发生在不同的时间,例如在编辑器中打开场景时和域重新加载后。

3 第一次帧更新之前

Start
调用时间:当一个MonoBehaviour实例被载入时,即场景加载时或实例化预制体时,Start被调用,仅调用一次,且在第一次帧更新前调用。
调用条件:游戏对象处于激活状态;游戏脚本处于启用状态。

2.2 物理更新阶段

unity生命周期,unity,游戏引擎

1 物理帧

FixedUpdate
FixedUpdate基于一个可靠的定时器被调用,独立于帧率之外(project->setting->Time,默认为0.02s,使用Time.fixedDeltaTime访问该值)。处理物体的物理属性(Rigidbody、Force、Collider)或者输入事件时,需要用FixedUpdate代替Update,以使物体的物理表现更平滑。

不过实际上,FixedUpdate并不是真的按照现实时间间隔执行的,它按照Timer时间间隔执行,而Timer并不是真正意义上的现实时间,它的作用是在运行环境下创造一个与现实时间高度相近的变量来实现物理帧的逻辑稳定。因为FixedUpdate的这个特质,建议在此环节只做物理相关的处理,不要把其他类型(如网络帧同步)的处理也放入此步骤。

2 触发/碰撞

OnTriggerXXX
触发器被触发时调用。

OnCollisionXXX
产生碰撞事件时调用。

3 协程:物理帧结束

Yield WaitForFixedUpdate
当物理帧执行完毕后会跳转到此协程,协程的调用跟方法是不同的,可以理解为在一段代码中设置一个卡点,当程序执行到这个卡点所匹配的时机时卡点后面的代码才会继续执行。

public class Test : MonoBehaviour{
    void Awake(){
    	//数字代表执行顺序
        Debug.Log("1");
        StartCoroutine(TestCoroutine());
        Debug.Log("3");
    }
    void FixedUpdate(){
        Debug.Log("4");
    }
    //协程
    IEnumerator TestCoroutine(){
        Debug.Log("2");
        yield return new WaitForFixedUpdate(); //卡点:物理帧结束
        Debug.Log("5");                      
    }
}

2.3 输入事件阶段

unity生命周期,unity,游戏引擎

鼠标、键盘、触屏、手柄等各类输入事件会在这个阶段触发,这个时间点物理更新已经执行(如果需要物理更新的话),而逻辑更新和渲染并未执行,要了解这个触发的时机,才能更好的掌握代码逻辑。

2.4 游戏逻辑阶段

unity生命周期,unity,游戏引擎

1 帧更新

Update
每帧调用1次,但由于系统性能以及游戏体量的区别,每一帧的刷新频率也是不同的,所以不要过分期待在Update方法中按时完成任务。

Update与FixedUpdate实际上是使用同一个线程的,update在loop中的处理方式是本次更新完毕再根据上一帧到现在的偏移时间判断是否进行下一次更新,Update的本质就是回调函数。只要是回调函数就存在上下文传递的损耗,所以如果想减少回调,可以考虑自己实现一套Update机制,使用虚函数来代替Update。

2 多协程点判断

1.yield null
2.yield WaitForSeconds
3.yield WWW:当网络任务执行完成后,会在当前帧的这个时间点执行WWW之后的操作。一般用于异步加载资源。
4.yield StartCoroutine

3 后更新

LateUpdate
每帧Update方法调用之后会调用本方法。LateUpdate一般用于二次计算,因为LateUpdate 开始时,在 Update 中执行的所有计算便已完成。

LateUpdate 的常见用途是第三人称摄像机跟随。如果在 Update 内让角色移动和转向,可以在 LateUpdate 中执行所有摄像机移动和旋转计算。这样可以确保角色在摄像机跟踪其位置之前已完全移动。

2.5 渲染阶段

unity生命周期,unity,游戏引擎
OnGUI
OnGUI()方法是在Unity的GUI系统渲染之前被调用的,一般用于在游戏界面中显示UI元素,例如按钮、标签、滑动条等。当需要在游戏界面中显示UI元素时,可以在OnGUI()方法中编写相关的代码。OGUI()每帧调用多次。

需要注意的是,OnGUI()方法只能在主线程中调用,不能在其他线程中调用,否则会导致程序异常。另外,由于OnGUI()方法的调用是由Unity的GUI系统自动触发的,因此不需要手动调用该方法。

另外,OnGUI函数在Unity的新版本中已被标记为“过时”(Deprecated),不推荐在新的项目中使用。推荐使用新的UI系统,如UGUI(Unity GUI)和IMGUI(Immediate Mode GUI)。

2.6 暂停阶段

unity生命周期,unity,游戏引擎
OnApplicationPause
在帧的结尾处调用此函数(在正常帧更新之间有效检测到暂停)。在调用 OnApplicationPause 之后,将发出一个额外帧,从而允许游戏显示图形来指示暂停状态。

2.7 退出阶段

unity生命周期,unity,游戏引擎
ApplicationQuit
当应用程序退出时,所有正在运行的场景和对象都将被销毁,包括挂在这些对象上的MonoBehaviour脚本。在这种情况下,如果需要在应用程序退出之前执行一些特定的操作,可以使用OnApplicationQuit函数来实现。在编辑器中,用户停止播放模式时,调用函数。

需要注意的是,当应用程序被强制关闭或崩溃时,OnApplicationQuit函数不会被调用。

OnDisable
在脚本或游戏对象被禁用时被调用,通常用于在游戏对象被禁用时执行一些清理操作或停止某些动作,例如停止音频播放、停止动画播放等。一般情况下,这些操作应该在OnEnable函数中启动,而在OnDisable函数中停止。这样可以保证在游戏对象被启用和禁用时,动作的开启和停止是对称的,避免出现意外的行为。

需要注意的是,OnDisable函数不会在游戏对象被销毁时被调用,因为在游戏对象被销毁时,所有与其相关的组件都会被销毁,包括脚本上的OnDisable函数。如果需要在游戏对象被销毁时执行一些清理操作,可以使用OnDestroy函数来实现。

OnDestory
在游戏对象被销毁时被调用。OnDestroy函数通常用于在游戏对象被销毁时执行一些清理操作或释放资源,例如关闭文件、释放内存等。

3 面试题

1. Awake和Start的区别?
① 调用时机不同。Awake在脚本实例被载入时就被调用,而Start在第一次帧更新前被调用。换句话说,Awake是在脚本实例出生时就被调用了,而Start是在帧上调用。举个例子,当我们在Update里实例化一个GameObject,Awake会在同一帧里马上被执行,而Start会在下一帧执行。
② 调用条件不同。Awake在脚本实例被载入时就被调用,无论脚本是否处于启用状态。而Start在脚本处于启用状态时才可被调用。
③ 用法不同。一般来说,我们在Awake中初始化变量或状态,但当我们需要延迟初始化或者获取其他游戏对象的组件时,可以使用Start。

2. Awake、Start和OnEnable的区别?
区别主要在于Awake和Start在一个物体的生命周期中仅被调用一次,当这个物体被取消激活再重新激活时,脚本里的Awake和Start都不会重新执行,而OnEnable则会在每次激活时执行。

3.现在场景内有两个物体,当场景载入时,它们的Awake函数会同时执行吗?
不会同时执行,会顺序执行,因为Unity是单线程的。而它们的执行顺序由Unity决定,满足一定条件时我们可以指定执行顺序。

而是否能够指定执行顺序主要取决于这两个对象是否为同一脚本的不同实例。
如果是:不能指定,这两个物体的事件函数的执行顺序是不一定的。
如果不是:可以指定。使用 Project Settings 窗口的 Script Execution Order 面板)。例如,如果有两个脚本,EngineBehaviour 和 SteeringBehaviour,可以设置 Script Execution Order,使 EngineBehaviours 始终在 SteeringBehaviours 之前更新。

另外,如果是一个物体的两个继承于MonoBehaviour的脚本,它们的Awake会按照脚本的添加顺序执行。

4.Update和FixedUpdate的区别?
Update()方法是在每一帧被渲染之前调用的,通常用于更新游戏对象的状态或行为,例如玩家输入、动画控制、音频播放等。由于它的调用时间不是固定的,取决于帧率和计算机性能,因此适合于处理非物理相关的计算。

而FixedUpdate()方法是根据固定时间间隔被调用的,一般默认为每秒50次。由于物理引擎的固定时间间隔是固定的,因此FixedUpdate()方法在每一帧中的调用次数是固定的,这使得它适合进行物理相关的计算,例如运动、碰撞检测等。

另外,与Update()方法不同,FixedUpdate()方法不能被暂停、恢复或禁用,因为它是基于物理引擎的固定时间间隔调用的。

5. 如果有多个物体需要进行碰撞检测,应该使用什么函数?
最常用的做法是使用物理引擎提供的碰撞检测机制,即给游戏对象添加Collider组件和Rigidbody组件,然后在脚本里使用OnCollisionXXX等事件函数来处理相关逻辑。

如果不使用物理引擎提供的碰撞检测机制,也可以使用Raycast或者OverlapSphere等函数来进行碰撞检测,不过这些函数需要手动调用,不属于Unity生命周期中的事件函数。

6. 什么是协程?
在Unity中,协程是一种特殊的函数,它可以在执行过程中暂停,并在指定的时间或条件满足时继续执行。Unity的协程是基于迭代器(yield)实现的,可以通过yield return语句来暂停协程的执行,并通过yield break语句来结束协程的执行。

协程的用途:

1.延时执行:协程可以在一定时间后执行指定的操作,例如延迟一定时间后执行动画播放、音效播放等操作。
2.动态加载资源:协程可以异步加载资源,并在资源加载完成后执行指定的操作,例如在游戏运行时动态加载场景、模型、贴图等资源。
3.动画控制:协程可以用来控制动画的播放,例如在一定时间内逐渐改变动画的状态、循环播放动画等。
4.多线程模拟:协程可以模拟多线程的效果,在主线程中执行协程并暂停,在另一个线程中执行指定的操作,例如下载文件、解压文件等操作。
5.协同工作:协程可以在不同的脚本之间进行协同工作,例如在一个脚本中控制另一个脚本的执行顺序和参数传递。

例子:
当玩家拿到一个道具时,我们想要显示一个“+1”的文字动画,然后等待一秒后自动消失。我们可以使用协程来实现这个效果。

public class PickupItem : MonoBehaviour{
    public GameObject pickupEffect;

    private void OnTriggerEnter(Collider other){
        if (other.CompareTag("Player")){
            // 播放拾取特效
            Instantiate(pickupEffect, transform.position, Quaternion.identity);
            // 开始协程
            StartCoroutine(DisplayText());
        }
    }
    IEnumerator DisplayText(){
        // 显示“+1”文本
        var text = GameObject.Instantiate(Resources.Load<GameObject>("Text"));
        text.transform.position = transform.position;
        text.GetComponent<TextMesh>().text = "+1";
        // 等待1秒
        yield return new WaitForSeconds(1f);
        // 销毁文本
        Destroy(text);
    }
}

7.如何在场景切换时管理生命周期?
①在场景中使用不同的游戏对象管理不同的功能和状态,从而使生命周期管理更加清晰和简单。
②在需要在场景切换时保留的游戏对象上使用DontDestroyOnLoad方法,这样这些游戏对象就不会在场景切换时被销毁。
③在需要在场景切换时销毁的游戏对象上使用SceneManager.LoadScene方法,这样这些游戏对象就会在场景切换时被销毁,从而避免资源泄漏和性能问题。
④在游戏对象上使用Awake和OnDestroy方法,在游戏对象被创建时执行一些初始化操作,在游戏对象被销毁时执行一些清理操作,以确保游戏对象在生命周期内始终处于正确的状态。

8.Unity生命周期与内存管理的关系?
在Unity中,当一个游戏对象或组件被创建时,它会被分配一定的内存空间来存储它的数据和状态。当这个游戏对象或组件不再需要时,Unity会自动将它们的内存空间释放,以便其他对象或组件可以使用这些内存空间。在这个过程中,生命周期起到了关键作用。例如,当一个游戏对象被销毁时,Unity会自动调用这个对象的OnDestroy方法,在这个方法中释放这个游戏对象占用的内存空间。类似地,当一个组件被禁用或销毁时,Unity也会自动释放这个组件占用的内存空间。

除了自动内存管理外,Unity还提供了一些手动内存管理的功能,例如资源管理、对象池等。这些功能可以帮助开发者更好地控制内存的使用和释放,从而提高游戏的性能和稳定性。文章来源地址https://www.toymoban.com/news/detail-674412.html

到了这里,关于【Unity学习日记01】Unity的生命周期的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 脚本的生命周期

    Unity 脚本的生命周期有哪些?什么时机会触发/执行?什么时候用? 手册 Unity 手册地址 生命周期 初始化 方法说明: Awake:当物体载入时立即调用一次,在 Start 函数之前调用。 OnEnable:在脚本对象启用时调用。 Start:仅当启用脚本实例时,才会在第一帧调用。 Reset:编辑器下

    2024年04月09日
    浏览(65)
  • Unity-生命周期

    Unity 中,有一个特别重要的知识点,生命周期函数。这些东西全部都是系统定义好的,运行时自动调用,但需要继承 MonoBehaviour 类才能使用。这个类是从 Unity 中创建脚本就自动继承了。 正是因为继承了 MonoBehaviour 这个类,Unity 才能依次调用我们的脚本代码,执行游戏逻辑。

    2024年02月03日
    浏览(34)
  • 【Unity】一文了解生命周期

    又新开一个坑,这个系列主要是记录Unity的干货,就不像之前那几个有点口水话了233 当然我会改正 时隔半个月 经历了开学 换教室等等一系列杂七杂八的事情也算步入正轨了~ 没杂七杂八的介绍什么,不水字数,直接开干!(暴论) 编写顺序会严格按照真实的生命周期顺序

    2023年04月22日
    浏览(28)
  • unity生命周期简单叙述

    1Awake(),2 OnEnable(), 3 Start(), 4 FixedUpdate(), 5 Update(), 6 LateUpdate(), 7 OnGUI(), 8 OnDisable(), 9 OnDestroy(). 特殊一点的方法Reset() Reset 方法是在编辑器中调用的,并且仅在以下情况下执行: 脚本组件被添加到 GameObject 上: 当你将一个脚本组件添加到一个 GameObject 上时,如果该脚本包含 Re

    2024年02月04日
    浏览(35)
  • 【Unity函数执行顺序(Unity脚本生命周期函数)】

    温故而知新,下面我将介绍Unity入门需要了解的常用生命周期函数 生命周期函数就是该脚本对象依附的GameObject对象从出生到消亡整个生命周期中 会通过反射自动调用的一些特殊函数。 下面是对各个函数解锁 a.调用情况: 1.在加载场景时初始化包含脚本激活状态的GameObject时。

    2023年04月23日
    浏览(47)
  • Unity之组件的生命周期

    PS:第二天,依旧在摸鱼学unity 我本身是由Web后端转到了游戏后端,最近因为工作原因在学ET框架。学到了 ECS 编程模式开发(E —— Entity,C —— Component , S —— System)实体、组件、逻辑开发。 我是这么理解的:组件是挂载到实体上的,组件中记录了实体所需要的数据,然

    2024年02月02日
    浏览(33)
  • Unity MonoBehaviour事件函数的生命周期

    Unity运行时候的默认的几个函数的执行顺序: 首先是Awake,OnEnable,Start等,后面是FixUpdate Update 最后是OnDisable、OnDestroy

    2024年02月10日
    浏览(40)
  • Unity 关于生命周期函数的一些认识

    Unity 生命周期函数主要有以下一些: Awake() : 在脚本被加载时调用。用于初始化对象的状态和引用。 OnEnable() : 在脚本组件被启用时调用。在脚本组件被激活时执行一次,以及在脚本组件被重新激活时执行。 Reset() : 在脚本组件被重置时调用。用于重置脚本的初始状态。 Start

    2024年01月21日
    浏览(48)
  • unity的函数生命周期以及静态生成方法

    前段时间毕业了,到处跑着玩,玩傻了之后入职了又摸了一个多月鱼~收收心了,近期的学习计划是下半年入门图形学,九月中旬把线性代数学完,所以unity和游戏开发的文章还是很少更新了,等后期学习图形学再慢慢更新和学习记录吧,中间工作中遇到的一些问题还是会记录

    2024年02月03日
    浏览(35)
  • Unity中常见的脚本生命周期函数及顺序

    以下是Unity中常见的脚本生命周期函数的顺序: Awake():当对象被创建时调用,用于初始化对象的引用和状态。 OnEnable():在对象变为激活状态时调用,用于进行初始化操作。 Start():在 Awake 之后调用,用于在对象被启用前进行初始化操作。 FixedUpdate():固定的时间间隔(一般

    2024年02月06日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包