生命周期函数与异步调用

一、Monobehaviour生命周期函数

在Unity中,MonoBehaviour是所有脚本的基类,它提供了一系列生命周期函数,这些函数在对象的生命周期中被自动调用。这些生命周期函数允许开发者在特定的时机执行代码,例如在对象被创建、启用、更新或销毁时。
以下是一些常用的MonoBehaviour生命周期函数:
 

1. Awake():

在对象被创建时调用,用于初始化对象。它在所有其他生命周期函数之前调用,通常用于初始化变量或设置初始状态。

2. Start():

在对象第一次被激活时调用。它在Awake()之后第一次Update()调用前调用,用于初始化一些需要在所有对象都已被创建后进行的操作。

3. Update():

在每一帧更新时调用。通常用于处理游戏逻辑、输入检测、动画更新等。Update()函数会在游戏每一帧被调用,因此它是频繁执行的函数。

4. FixedUpdate():

在固定时间间隔内调用。通常用于物理相关的操作,比如移动刚体、施加力等。FixedUpdate()的执行间隔由物理引擎决定,通常默认为每秒50次。

5. LateUpdate():

在Update()函数执行完毕后调用。通常用于处理在Update()中进行修改后的逻辑,例如跟随相机移动、处理角色控制等。

6. OnEnable()和OnDisable():

OnEnable()在对象激活时被调用,OnDisable()在对象被禁用时被调用

7. OnDestroy():

当对象被销毁时调用。通常用于清理资源、取消订阅事件等释放操作。

8.OnCollisionEnter(Collision collision):

当物体碰撞进入时调用

9. OnTriggerEnter(Collider other)

当触发器被进入时调用

using UnityEngine;
public class ExampleScript : MonoBehaviour
{
	private void Awake()
	{
		// 初始化操作
	}
	private void Start()
	{
		// 启动时的初始化操作
	}
	private void Update()
	{
		// 每帧更新操作
	}
	private void FixedUpdate()
	{
		// 每固定帧率更新操作
	}
	private void LateUpdate()
	{
		// 在所有Update调用后执行
	}
	private void OnDisable()
	{
		// 当脚本所附加的物体被禁用时执行
	}
	private void OnDestroy()
	{
		// 当脚本所附加的物体被销毁时执行
	}
	private void OnCollisionEnter(Collision 		collisionInfo)
	{
		// 当物体碰撞进入时执行
	}
// 其他函数可以根据需要添加...
}

这些函数可以根据你的具体需求进行重写,以添加自定义的行为。记住,在重写这些函数时,要确保代码不会引起长时间的阻塞,因为这会影响Unity的主更新循环,导致帧率下降。

二、异步调用Invoke

Invoke 函数是 MonoBehaviour 类中的一个方法,用于在指定时间后调用特定的方法,例如执行某些初始化操作、在一段时间后触发特定事件等。

它的一般形式如下:

public void Invoke(string methodName, float time);
public void InvokeRepeating(string methodName, float time, float repeatRate);
  • methodName 参数是要调用的方法的名称。
  • time 参数是在多长时间后开始调用指定方法,单位为秒。
  • repeatRate 参数仅适用于 InvokeRepeating 方法,表示方法的调用重复间隔时间,单位为秒。

CancelInvoke 方法是用于取消通过 InvokeInvokeRepeating 启动的调用计划的方法

public void CancelInvoke(string methodName) //取消名为MethodName的方法调用
public void CancelInvoke() //取消所有通过 Invoke或InvokeRepeating调用的方法

下面是一个简单的例子,展示了 Invoke 函数的用法:

using UnityEngine;
public class Example : MonoBehaviour
{
	void Start()
	{
		// 在2秒后调用名为 "MyMethod" 的方法
		Invoke("MyMethod", 2.0f);
		// 在5秒后每隔2秒重复调用名为 "RepeatedMethod" 的方法
		InvokeRepeating("RepeatedMethod", 5.0f, 2.0f);
		// 在10秒后取消所有通过 Invoke 或 InvokeRepeating 安排的方法调用计划
		Invoke("CancelAllInvoke", 10.0f);
	}
	void MyMethod()
	{
		Debug.Log("MyMethod was called!");
	}
	void RepeatedMethod()
	{
		Debug.Log("RepeatedMethod was called!");
	}
}

在这个例子中, MyMethod 方法会在游戏启动后的2秒钟后被调用一次,而 RepeatedMethod 方法会在游戏启动后的5秒钟后开始被调用,然后每隔2秒钟被重复调用一次。
注意:无论是游戏对象失活或者是脚本组件失活都不会停止Invoke调用过的函数,除非脚本或者游戏对象销毁即可停止

三、协程函数

在Unity中,协程(Coroutine)是一种特殊的函数,用于在一段时间内暂停执行,并在稍后的时间点继续执行。通常情况下,我们在代码中通过调用协程来实现一些需要延迟执行或需要分步处理的任务。协程在Unity中有如下特点:

  • 可以在一帧中的不同时间点暂停和恢复执行,而不需要等待整个帧的结束。
  • 可以方便地实现延迟执行,例如在几秒后播放音效或执行一个动画。
  • 可以使用协程来实现复杂的异步任务,而不需要使用回调函数或依赖于线程

协程的使用如下所示:

1. 在脚本中定义协程函数,函数必须返回IEnumerator类型,并使用yield语句中断执行流程。

yield语句的作用是暂停协程的执行,等待指定的时间或事件结束后再次执行协程。

 

private IEnumerator MyCoroutine()
{
	// 执行一些操作
	yield return new WaitForSeconds(2.0f);
	// 等待 2 秒后执行下一步操作
	Debug.Log("等待了2秒后继续执行");
	yield return new WaitForSeconds(1.0f);
	Debug.Log("又等待了1秒后继续执行");
}

2. 在其他函数中通过 StartCoroutine() 启动协程函数并控制协程的开始和停止。

例如:

private void Start()
{
	// 启动协程函数 MyCoroutine()
	StartCoroutine(MyCoroutine());
}
private void Update()
{
	// 在 Update() 函数中控制协程的开始和停止
	if (Input.GetKeyDown(KeyCode.Space))
	{
		// 停止协程函数 MyCoroutine()
		StopCoroutine(MyCoroutine());
	}
}

3. 协程的挂起

//程序在下一帧中从当前位置继续执行
yield return 0;
//程序在下一帧中从当前位置继续执行
yield return null;
//程序等待N秒后从当前位置继续执行
yield return new WaitForSeconds(N);
//在所有的渲染以及GUI程序执行完成后从当前位置继续执行
yield new WaitForEndOfFrame();
//所有脚本中的FixedUpdate()函数都被执行后从当前位置继续执行
yield new WaitForFixedUpdate();
//等待一个网络请求完成后从当前位置继续执行
yield return WWW;
//等待一个xxx的协程执行完成后从当前位置继续执行
yield return StartCoroutine(xxx);
//如果使用yield break语句,当不满足执行条件时直接从当前位置跳出函数体,回到函数的根部
yield break;

4. 协程使用的场合:

  • 控制游戏对象的缓慢移动、旋转等动画效果。
  • 实现计时器、等待操作等功能。
  • 遍历复杂的数据结构或者进行其他需要分散处理的操作。
  • 当协程的数量过多时,可能会对游戏资源造成较大的压力。

5. 协程和线程的区别

  • 执行方式:线程是由操作系统调度的最小执行单位,它在操作系统的控制下运行,可以并行执行。协程是由程序控制的执行单位,它由程序自己在协程调度器的管理下运行,可以通过协作方式实现并发。
  • 并发性:线程可以在多个 CPU 核心上并行执行,利用多核优势提高计算效率。而协程通常在单个线程中运行,通过在不同协程间的切换实现并发,无法利用多核优势。
  • 内存和资源消耗:线程在创建时需要分配独立的内存空间,包括堆栈等资源,同时线程切换时需要保存和恢复上下文,消耗较多的内存和资源。协程则可以在一个线程中存在多个,共享同一堆栈空间,切换时只需要保存和恢复少量上下文,消耗较少的内存和资源。
  • 同步与通信:在线程中,由于存在资源竞争,需要使用锁机制等同步手段来保护共享资源,避免数据冲突。协程通过显式地让出执行权和恢复执行权来避免资源竞争,并通过通道(channel)等机制进行协程间的通信。

“您的支持是我持续分享的动力”

微信收款码
微信
支付宝收款码
支付宝

目录