欢迎来到我的博客小站。  交流请加我微信好友: studyjava。  也欢迎关注同名公众号:Java学习之道

学Unity的猫之脚本组件的生命周期(四

  |   0 评论   |   0 浏览

4.1 怎么没有老鼠组件

我:“皮皮,你在干嘛?”
皮皮:“我在给物体挂组件,可是我找了半天,也没找到老鼠组件。”
我:“哈哈哈,Unity没有帮我们实现老鼠的组件,需要我们自己写。”
皮皮:“那我们赶紧写一个老鼠组件吧。”
我:“没问题的,但在这之前,你得先搞明白什么是组件,它的运行机制。”

4.2 Component——组件

Component,组件,顾名思义,就是游戏物体的组成部件。
我拿出扫地机器人,对着皮皮说:“你看这个扫地机器人,它会寻路移动、扫地、避开障碍物、充电等等,它之所以具备这些功能,是因为它有轮子、边刷、激光测距传感器、电源等等这些组件,这些组件拼装在一起通过合理的协同工作,才完整地构成了一台扫地机器人,游戏物体也一样。”
我打开Unity工程,然后选中Main Camera节点,接着说:“看这里,这个Main Camera,它是一个游戏对象,它身上挂了三个组件:TransformCameraAudioListener。”

皮皮:“那一只老鼠要挂多少组件呢?”
我:“这个要看需求和设计,你可以一个组件只实现一个单一的功能,然后挂很多组件,也可以把多个功能合理地整合在一个组件里,只挂这个组件。顺便说一句,所有物体都必须带一个Transform组件。”
皮皮似懂非懂地点点头,我摸摸皮皮的小脑袋,接着说:“还有,组件也不能滥用,新手容易犯的一个错误就是组件泛滥。优秀的程序员,会懂得合理地使用设计模式,优雅地抽象、封装,把代码打理得干净漂亮,你们喵星人都自带洁癖属性,我觉得你会是一个优秀的程序员的。”
皮皮:“是不是所有的脚本都是Component组件?”
我:“不是的,你注意看,我们创建的脚本,默认是继承MonoBehaviour的。”

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

public class NewBehaviourScript : MonoBehaviour
{
    
    void Start()
    {
       
    }

    
    void Update()
    {
        
    }
}

皮皮:“Component组件,和这个MonoBehaviour又是什么关系呢?”
我:“问的好,这里就要介绍一下Unity中的类继承关系了。”
我拿出一张白纸,在纸上画了Unity中的部分类继承关系。

Unity中,所有实体最上层的基类是ObjectComponent继承ObjectBehavior继承ComponentMonoBehavior继承Behavior

注意这里的Object是指UnityEngine.Object,有别于.NetSystem.object。事实上,UnityEngine.Object也是一个System.object,但一个System.object不一定是一个UnityEngine.Object
比如:
string a = "hello cat";
a是一个System.object,但它不是一个UnityEngine.Object

皮皮:“晕了晕了,简直就是俄罗斯套娃啊。”
我:“哈哈,所以呢,继承MonoBehaviour的脚本就是Component组件,Unity封装的MonoBehaviour还提供了协程的功能,这个后面我再教你。”
我打开Visual Studio继续说,:“在实际开发过程中,我们也会创建一些不是继承MonoBehaviour的脚本,这些脚本就不是Component,比如我现在封装一个静态的工具类:GameUtils。”

using System;

public class GameUtils 
{
  
    public static string GetNowTime()
    {
        return DateTime.Now.ToString();
    }
}

GameUtils.cs是一个脚本,但它不是一个组件。只有组件才可以AddComponent(挂组件)到物体上,同时,组件要挂到物体上才能真正被运行起来。

4.3 MonoBehaviour脚本的生命周期

皮皮:“你刚刚说组件要挂到物体上才能真正被运行起来,那它是怎么运行的呢?”
我:“这里就要讲讲MonoBehaviour脚本的生命周期了。”
可以参见Unity官方文档的说明:
https://docs.unity3d.com/Manual/ExecutionOrder.html

原图地址:https://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg
皮皮:“铲屎官,郑现在再封你一个官!”
我:“嗯?”
皮皮:“翻译官。”
我:“我挑重点,一个一个函数来吧。”

4.3.1 Reset()函数

Reset,重置函数,这个函数只有在Editor环境下才会被调用,运行过程中是不会调用Reset的。
它是在用户点击Inspector面板上Reset按钮或者首次添加该组件时被调用。Reset最常用于在Inspector面板中给定一个默认值。

4.3.2 Awake()函数

Awake,唤醒函数,注意它只会被执行一次,这个要牢记。当游戏对象被创建的时候, 游戏对象绑定的脚本会在该帧内执行Awake函数。

如果脚本所挂的物体最开始不是激活状态,则Awake函数此时不会被调用,激活物体时才会被调用。在Inspector窗口的最左上方,有个勾选,如果不勾选,则表示隐藏物体。
如下,物体处于隐藏状态,此时运行UnityNewBehaviourScript脚本中的Awake函数并不会被调用,激活物体时,Awake函数才会被调用。

值得一提的是,如果物体是激活状态,然后脚本是非激活状态,此时运行UnityNewBehaviourScript脚本中的Awake函数是会被调用的。
如下,Awake函数照样会被执行。

4.3.3 OnEnable()函数

OnEnable,激活函数, 当脚本激活时被调用,激活一次就调用一次,激活n次,OnEnable就调用n次。调用顺序在Awake之后。

4.3.4 Start()函数

Start,启动函数,Start函数的调用位于Awake函数之后,Start函数会在Update函数第一帧之前被调用,与Awake函数一样只会被调用一次,与Awake函数不一样的是当脚本最开始处于不激活状态,Awake函数会被调用,而Start函数不会被调用,只有激活了脚本才会调用Start函数。

4.3.5 Update()函数

Update,帧更新函数,每一帧都会被调用。只有物体和脚本都处于激活状态下才会被调用。调用顺序在Start函数之后,之后就每帧调用Update函数,帧与帧之间的时间间隔不是固定的,收到运行时的CPUGPU等工作负荷的影响,我们常说的卡顿,就是运行负荷太高了,此时帧与帧之间的间隔时间就会变大,出现掉帧的情况。

4.3.6 LateUpdate()函数

LateUpdate,延迟更新函数,LateUpdate函数会在Update函数结束之后被调用,LateUpdate常用为第三人称视角相机跟随,比如在Update中处理主角的移动,在LateUpdate中处理摄像机跟随移动。

4.3.7 FixedUpdate()函数

FixedUpdate,固定更新函数,在游戏运行的过程中, 每一帧的处理时间是不固定的, 当我们需要固定间隔时间执行某些代码时, 就会用到FixedUpdate函数。
FixedUpdate的调用时间间隔,可以在编辑器中设置。点击菜单Edit - Project Settings...,然后点击Time,可以看到有个Fixed Timestep,它就是FixedUpdate的调用时间间隔,默认是0.02秒

4.3.8 OnGUI()函数

OnGUI,绘制界面函数。一般作为测试功能使用, 如创建测试按钮。
例:

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

public class NewBehaviourScript : MonoBehaviour
{
    private void OnGUI()
    {
        if(GUILayout.Button("我是一个测试按钮"))
        {
            Debug.Log("我被点击啦");
        }
    }
}

4.3.9 OnDisable()函数

OnDisable,当脚本被禁用时调用。在Inspector窗口中,脚本前面的勾选框,就可以激活和禁用脚本。它与OnEnable函数是对应的。

4.3.10 OnDestroy()函数

OnDestroy,当脚本所在的物体被销毁或者脚本本身被移除的时候,OnDestroy函数被调用。

4.4 测试生命周期

皮皮:“感慨呀,每一个脚本都是一条生命呀。”
我:“人生苦短,莫要虚度年华,来,跟着我跑一遍测试脚本,我们来跑一下脚本组件的生命周期测试。”
示例代码:

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    private bool hasPrintUpdate = false;
    private bool hasPrintLateUpdate = false;
    private bool hasPrintFixedUpdate = false;
    private bool hasPrintGUI = false;

    void Awake()
    {
        Debug.Log("---Awake---");
    }

    void OnEnable()
    {
        Debug.Log("---OnEnable---");
    }

    void Start()
    {
        Debug.Log("---Start---");
    }

    void FixedUpdate()
    {
        if (!hasPrintFixedUpdate)
        {
            hasPrintFixedUpdate = true;
            Debug.Log("---FixedUpdate---");
        }
    }

    void Update()
    {
        if (!hasPrintUpdate)
        {
            hasPrintUpdate = true;
            Debug.Log("---Update---");
        }
    }

    void LateUpdate()
    {
        if (!hasPrintLateUpdate)
        {
            hasPrintLateUpdate = true;
            Debug.Log("---LateUpdate---");
        }
    }

    void OnGUI()
    {
        if (!hasPrintGUI)
        {
            hasPrintGUI = true;
            Debug.Log("---OnGUI---");
        }
    }

    void OnDisable()
    {
        Debug.Log("---OnDisable---");
    }

    void OnDestroy()
    {
        Debug.Log("---OnDestroy---");
    }
}

运行结果如下:

---Awake---
---OnEnable---
---Start---
---FixedUpdate---
---Update---
---LateUpdate---
---OnGUI---
---OnDisable---
---OnDestroy---

标题:学Unity的猫之脚本组件的生命周期(四
作者:shirlnGame
地址:https://mmzsblog.cn/articles/2021/01/05/1609855298253.html
-----------------------------
如未加特殊说明,此网站文章均为原创。
网站转载须在文章起始位置标注作者及原文连接,否则保留追究法律责任的权利。
公众号转载请联系网站首页的微信号申请白名单!

个人微信公众号 ↓↓↓                 

微信搜一搜爱上游戏开发