一文读懂Unity常用生命周期函数! 超级详细、不服来辩~

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 零基础学习Unity常用什么周期函数,超级详细的解析,不看会后悔哦~

一,初始化

1.1 函数描述

运行状态初始化:(也是执行顺序)

  1. Awake:初始化时调用,在Start函数之前调用
  2. OnEnable:在对象启用时调用
  3. Start:仅当启用脚本实例时,才会在第一帧调用

编辑器状态初始化

  1. Reset:编辑器下调用,当脚本第一次附加到物体上或者点击Reset时执行,来初始化脚本属性。

实际应用

  1. Awake:通常使用为需要提前初始化的逻辑。比如单例赋值
    private void Awake(){Instance = this;}
  2. OnEnable:处理每次显示时都需要进行初始化的逻辑,通常和OnDisable配合使用。
    比如: 游戏逻辑使用并修改了变量Number,而下次显示时使用是又需要Number = 1,此时就可以写private void Awake(){Number = 1;}
  3. Start:通常使用为一些变量初始化逻辑。

    比如:获取指定物体:`private void Start(){child1 = transform.GetChild(0);}`
  4. Reset:通常在游戏测试调试时,使用编辑器下的初始化。通过点击Reset执行一个逻辑。

1.2 示例解析

运行状态初始化示例:
  搭建场景新建两个UI -> Image,一个作为背景,一个作为弹窗。新建脚本并挂载到弹窗Image上。

脚本内容如下:

using UnityEngine;

public class LifeCycleFunction : MonoBehaviour
{
    #region Initialization 初始化
    public int Number = 1;
     
    private void Awake()
    {
        Debug.Log("Awake 初始化时调用,在Start函数之前调用,...");
    }
    private void OnEnable()
    {
        Debug.Log("OnEnable 每次对象启用都会被调用...");
    }
    private void Reset()
    {
        Number = 0;
        Debug.Log("Reset 编辑器模式下才可被调用...Number: " + Number);
    }
    private void Start()
    {
        Debug.Log("Start 仅当启用脚本实例时,才会在第一帧调用...");
    }
    
    #endregion
}

此次运行结果展示了Awake,OnEnable,Start 的执行顺序,运行结果:

编辑器下的初始化:
1.脚本拖拽附加时自动执行

2.点击Reset调用: 可以看到我手动Number设置为2,Reset后被重置为代码中写的0;


二,更新

2.1 函数描述

三个函数

  1. FixedUpdate:固定时间调用,FixedUpdate通常比Update更频繁地调用
  2. Update:每帧调用一次
  3. LateUpdate:在Update完成后,每帧调用一次

实际应用

  1. FixedUpdate:所有物理计算和更新都在FixedUpdate中处理。它是固定时间调用,不会受到帧率影响。比如:一些物理属性的更新操作Force,Collider,Rigidbody等。
  2. Update:每帧调用一次,根据帧率的快慢影响执行速度。通常的游戏逻辑都写在这里,比如:和玩家交换,当用户按下空格时进行执行什么操作。
  3. LateUpdate:每次Update完成后调用移除。常见用处是相机跟随主角,比如:主角在Update中移动,则可以在LateUpdate执行相机的移动,这将可以保证摄像机跟着的时候之前的逻辑一起完全执行完成。

2.2 示例解析

将如下脚本添加到上面新建的脚本中:(为了方便查看,将上面初始化的函数先注释掉)

#region 更新

// 固定时间调用,FixedUpdate通常比Update更频繁地调用
private void FixedUpdate()
{
    Debug.Log("FixedUpdate 固定时间调用...");
}
// 每帧调用一次
private void Update()
{
    Debug.Log("Update 每帧调用一次...");
}
// 在Update后,每帧调用一次 
private void LateUpdate()
{
    Debug.Log("LateUpdate 在Update后,每帧调用一次...");
}
#endregion

运行后,可以看到结果如下:


三,鼠标交互

3.1 函数描述

几个函数

  1. OnMouseEnter: 鼠标进入时调用一次
  2. OnMouseOver: 鼠标停留(经过)时一直调用
  3. OnMouseExit: 鼠标退出时调用一次
  4. OnMouseDown: 鼠标按下时调用一次
  5. OnMouseDrag: 鼠标拖拽(按住)时一直调用
  6. OnMouseUp: 鼠标抬起时调用一次

实际使用:使用时一般都是成对使用

  1. OnMouseEnter,OnMouseOver,OnMouseExit 一组。比如模拟选中状态:鼠标进入时物体变色,鼠标退出时再变回来。
  2. OnMouseDown,OnMouseDrag,OnMouseUp 一组。比如射击游戏:鼠标按下拖拽时调整方向,抬起时发射子弹。
  3. 当鼠标按下并停留在当前游戏对象上时,OnMouseOver,OnMouseDrag会同时触发。

检测原理

  1. 只能检测当前脚本挂载的游戏对象。
  2. 当前游戏对象需要有碰撞体。
  3. 不能有其他物体(UI)遮挡到此游戏对象。
  • 总结为一局话就是:OnMouseXXX的原理是通过鼠标的射线检测来判断鼠标当前位置是否碰到了挂载脚本游戏对象的碰撞体。

勾选IsTrigger:

  若需要不检测勾选IsTrigger的碰撞体,Edit => Project Settings => Physics中的Queries Hit Triggers,将这个✅ 取消,即可不触发勾选IsTrigger的。【注意:默认是✅ 勾选状态,不需要触发则取消勾选】


3.2 示例解析

  场景中创建一个Cube,将其位置调整在摄像机先显示即可【示例中调整位置(0,0,-1),缩放为(3,3,3)】。

测试功能:

  • 鼠标进入\退出,触发Cube颜色变化
  • 鼠标移动到Cube上,触发旋转
  • 鼠标在Cube按下并拖拽,触发Cube跟随移动
  • 鼠标抬起Cube回归到原来位置

创建并挂载到Cube代码如下:

using UnityEngine;

public class OnMouseXXXTest : MonoBehaviour
{
    #region 鼠标相关

    // 鼠标和Collider(碰撞体)之间的触发
    
    // 鼠标进入
    private void OnMouseEnter()
    {
        Debug.Log("OnMouseEnter 鼠标进入...");
        GetComponent<MeshRenderer>().material.color = Color.blue;
    }
    
    // 鼠标停留
    private void OnMouseOver()
    {
        transform.Rotate(Vector3.up * 50 * Time.deltaTime);
    }

    // 鼠标退出
    private void OnMouseExit()
    {
        Debug.Log("OnMouseExit 鼠标退出...");
        GetComponent<MeshRenderer>().material.color = Color.green;
    }

    // 鼠标按下
    private void OnMouseDown()
    {
        Debug.Log("OnMouseDown 鼠标按下...");
    }

    // 鼠标拖动
    private void OnMouseDrag()
    {
        Vector3 target = Input.mousePosition;
        target.z = Mathf.Abs(Camera.main.transform.position.z);
        transform.localPosition = Camera.main.ScreenToWorldPoint(target);
    }

    // 鼠标抬起
    private void OnMouseUp()
    {
        Debug.Log("OnMouseUp 鼠标抬起...");
        transform.localPosition = new Vector3(0, 0, -1);
    }

    #endregion
}

测试效果:


四,碰撞检测

4.1 函数描述

碰撞函数

  1. OnCollisionEnter: 进入碰撞时触发一次。
  2. OnCollisionStay: 在碰撞体中停留时每帧触发一次。
  3. OnCollisionExit: 离开碰撞体时触发一次。

触发函数

  1. OnTriggerEnter: 进入碰撞体时触发一次。
  2. OnTriggerStay: 在碰撞体中停留时每帧触发一次。
  3. OnTriggerExit: 离开碰撞体是触发一次。

PS:上面这六个方法,还有对应2D碰撞体的六个方法(如:OnCollisionEnter2D) 函数后面添加2D接口,触发条件和使用方式和3D一致。 使用时注意碰撞体和检测函数同步接口,即用2D碰撞体必须用2D函数。

函数执行条件

  1. 两个物体需要都有碰撞体(Collider)组件。
  2. 检测方(挂载脚本物体)需要有刚体(Rigidbody)组件。
  3. Collider上都不勾选IsTrigger(有一方勾选则执行触发函数)。

4.2 示例解析

在三例上继续操作,在Cube上添加Rigidbody组件,并取消勾选Use Gravity 属性(避免其受到重力影响)。

然后再创建两个Cube,位置大小随意能在Game视图看到就行。将其中一个BoxCollider的IsTrigger 属性勾选 ✅ 上。这样就可以一个用来测试碰撞,一个用来测试触发了。

将代码添加到OnMouseXXXTest类中,添加内容如下:

#region 碰撞,触发检测

// 在方法名后加上2D(如:OnCollisionEnter2D), 即可触发2D碰撞体对应函数
// 进入碰撞时触发
private void OnCollisionEnter(Collision other)
{
    Debug.Log("开始碰撞..." + other.collider.gameObject.name);
    other.collider.GetComponent<MeshRenderer>().material.color = Color.black;
}

// 在碰撞体中停留时每帧触发一次
private void OnCollisionStay(Collision other)
{
    Debug.Log("持续碰撞中..." + other.collider.gameObject.name);
    other.collider.GetComponent<MeshRenderer>().material.color = Color.red;
}

// 离开碰撞体时触发
private void OnCollisionExit(Collision other)
{
    Debug.Log("碰撞结束..." + other.collider.gameObject.name);
    other.collider.GetComponent<MeshRenderer>().material.color = Color.white;
}

// 碰撞体勾选is Trigger 选项: 取消碰撞器,开启触发器
// 进入碰撞体时触发
private void OnTriggerEnter(Collider other)
{
    Debug.Log("触发开始...");
    other.transform.GetComponent<MeshRenderer>().material.color = Color.black;
}

// 在碰撞体中触发
private void OnTriggerStay(Collider other)
{
    Debug.Log("持续触发中...");
    other.transform.GetComponent<MeshRenderer>().material.color = Color.yellow;
}

// 离开碰撞体是触发
private void OnTriggerExit(Collider other)
{
    Debug.Log("触发结束...");
    other.transform.GetComponent<MeshRenderer>().material.color = Color.white;
}
#endregion

运行后得到如下效果:


五,应用程序

5.1 函数描述

三个函数

  1. OnApplicationPause: 检测到暂停的帧结束 --> 切换到后台和回来时调用。
  2. OnApplicationFocus: 当屏幕 获得/失去 焦点时调用
  3. OnApplicationQuit: 当程序退出时调用。

实际应用

  1. OnApplicationPause: 游戏停止保存数据/游戏继续数据初始化。
  2. OnApplicationFocus: 失去焦点关闭背景音乐/获得焦点继续播放音乐。
  3. OnApplicationQuit: 在移动端大退时也会对调用,但不会触发上面两个方法。

5.2 示例解析

使用时将下面代码复制到需要处理检测逻辑的部分即可:

#region Application 应用程序

// 检测到暂停的帧结束时调用,有效地在正常帧更新之间
private void OnApplicationPause(bool pauseStatus)
{
    Debug.Log("OnApplicationPause ... " + pauseStatus);
    if (pauseStatus) // 切换到后台时执行
    {
    }
    else // 切换到前台执行一次
    {
    }
}

// 当屏幕 获得/失去 焦点时调用
private void OnApplicationFocus(bool hasFocus)
{
    Debug.Log("OnApplicationFocus ... " + hasFocus);
    if (hasFocus) // 获得焦点 -- 切换到前台
    {
    }
    else // 失去焦点
    {
    }
}

// 当程序退出时调用 -- Application.Quit();触发,不会触发上面两个方法
private void OnApplicationQuit()
{
    Debug.Log("OnApplicationQuit ... ");
}

由下图可以看到执行逻辑:当我点击Hierarchy面板时触发失去焦点,再次点击Game视图则触发了获得焦点


六,禁用销毁

6.1 函数描述

三个函数

  1. OnDisable: 当对象被禁用时调用此函数(其父物体被禁用也会触发)。
  2. OnDestroy: 在对象存在的最后一帧的所有帧更新之后调用此函数。

实际应用

  1. OnDisable: 通常和OnEnable配合使用。比如:在OnEnable添加监听,在OnDisable移除监听
  2. OnDestroy: 当物体销毁或者场景关闭时触发。比如:子弹打到墙壁时,需要销毁子弹并触发一个打击音效。

6.2 示例解析

1.游戏物体禁用触发OnDisable

2.游戏物体销毁时触发OnDisableOnDestroy


Unity 官方图解:
图解

怎么样?是不是收获颇丰。本文对你有帮助的话,欢迎小伙伴们三连支持一下。有问题的话我们评论见吧~
相关文章
|
3月前
|
API 开发工具 图形学
PicoVR Unity SDK⭐️五、常用API接口函数一览
PicoVR Unity SDK⭐️五、常用API接口函数一览
|
2月前
|
图形学 开发者 UED
Unity游戏开发必备技巧:深度解析事件系统运用之道,从生命周期回调到自定义事件,打造高效逻辑与流畅交互的全方位指南
【8月更文挑战第31天】在游戏开发中,事件系统是连接游戏逻辑与用户交互的关键。Unity提供了多种机制处理事件,如MonoBehaviour生命周期回调、事件系统组件及自定义事件。本文介绍如何有效利用这些机制,包括创建自定义事件和使用Unity内置事件系统提升游戏体验。通过合理安排代码执行时机,如在Awake、Start等方法中初始化组件,以及使用委托和事件处理复杂逻辑,可以使游戏更加高效且逻辑清晰。掌握这些技巧有助于开发者更好地应对游戏开发挑战。
120 0
|
3月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
77 0
|
5月前
|
程序员 图形学 Android开发
Unity脚本生命周期
Unity脚本生命周期
|
11月前
|
图形学
Unity 脚本的生命周期
Unity 脚本的生命周期
|
API 图形学
【unity每日一记】—线性差值函数以及平滑阻尼的运用和实践(Lerp AND SmoothDamp)
【unity每日一记】—线性差值函数以及平滑阻尼的运用和实践(Lerp AND SmoothDamp)
304 0
|
图形学 C++
Unity-生命周期
Unity-生命周期
124 0
|
Java API 图形学
Unity WebGL 程序如何调用Java Script函数
Unity WebGL 程序如何调用Java Script函数
226 1
Unity WebGL 程序如何调用Java Script函数
|
Java 图形学
Unity打包符号表 使用ndk addr2line.exe+符号表 将崩溃内存地址解析成函数名
符号表的路径,符号表发布出来的时候是一个zip文件要把它解压出来,里面会有两个文件:arm64-v8a(64位)、armeabi-v7a(32位)不过unity默认打包出来的都是64位的程序,所以这个前面加上你的真实路径+arm64-v8a\libil2cpp.sym.so就可以了。