一、什么是协程?
协程是一种特殊的函数,其执行可以被暂停和恢复,适用于需要等待某个条件或时间的场景。在 Unity 中,协程通常用于处理时间延迟、动画、网络请求等不需要阻塞主线程的任务。
二、基本用法
1. 启动协程:
使用 StartCoroutine() 方法来启动一个协程。协程通常返回 IEnumerator 类型。
如:StartCoroutine( MyCoroutine() );
2. 定义协程:
在协程中,可以使用 yield 语句来暂停执行,直到满足某个条件或时间到达。
IEnumerator MyCoroutine()
{
print("开始");
yield return new WaitForSeconds(2); // 等待2秒
print("结束");
}
3. 使用不同的 yield:
Unity 提供了多种 yield 类型,最常见的包括:
yield return null;:在下一帧继续执行。
yield return new WaitForSeconds(float seconds);:等待指定的时间。
yield return new WaitForEndOfFrame();:在当前帧结束后执行。
yield return new WaitUntil(Funcpredicate);:等待直到条件为真。
三、协程的优势
1. 非阻塞执行:协程允许你在不阻塞主线程的情况下执行长时间运行的任务,比如等待时间、动画等,使得游戏依然保持流畅。
2. 易于编写和理解:使用协程可以使代码看起来更加清晰,因为它避免了回调地狱(callback hell),并且逻辑更接近于顺序执行。
3. 灵活性:协程可以在多个帧之间分配工作,适合处理复杂的异步逻辑。
四、注意事项
1. 生命周期:协程的生命周期与启动它的 MonoBehaviour 组件相同。如果该组件被禁用或销毁,协程将自动停止。
2. 性能:虽然协程相对高效,但仍然需要注意过多的协程可能会影响性能,特别是在每帧都需要大量协程的情况下。
五、应用范例
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class Test : MonoBehaviour
{
bool IsWaitingA;
bool IsWaitingB;
// Start is called before the first frame update
void Start()
{
IsWaitingA = true;
IsWaitingB = true;
StartCoroutine(Task());
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
IsWaitingA = false;
}
if (Input.GetKeyDown(KeyCode.B))
{
IsWaitingB = false;
}
}
IEnumerator Task()
{
while (IsWaitingA)
{
print("Waiting A");
yield return null;
}
print("IsWaitingA ------ > OK");
while (IsWaitingB)
{
print("Waiting B");
yield return null;
}
print("IsWaitingB ------ > OK");
}
}
以上代码示例展示了如何使用协程来处理多个等待状态,通过用户输入控制协程的执行流。按下不同的键会影响协程的行为,使得代码在游戏中实现了简单的状态等待逻辑。
六、代码结构
字段定义:
bool IsWaitingA:用于控制协程是否在等待 A 事件。
bool IsWaitingB:用于控制协程是否在等待 B 事件。
Start 方法:
在游戏开始时,IsWaitingA 和 IsWaitingB 都被初始化为 true,表示当前都在等待。
启动 Task 协程。
Update 方法:
每帧检查是否按下了 A 键或 B 键。
如果按下 A 键,IsWaitingA 被设置为 false,表示不再等待 A。
如果按下 B 键,IsWaitingB 被设置为 false,表示不再等待 B。
Task 协程:
- 首先进入第一个 while (IsWaitingA) 循环:
- 只要 IsWaitingA 为 true,就会打印 “Waiting A”。
- yield return null; 使协程暂停,等待下一帧继续执行。
- 一旦按下 A 键,IsWaitingA 变为 false,循环结束,打印 “IsWaitingA —— > OK”。
- 然后进入第二个 while (IsWaitingB) 循环:
- 只要 IsWaitingB 为 true,就会打印 “Waiting B”。
- 同样使用 yield return null; 暂停,等待下一帧。
- 一旦按下 B 键,IsWaitingB 变为 false,循环结束,打印 “IsWaitingB —— > OK”。
七、运行逻辑总结
(a) 启动时:脚本启动,初始化两个等待状态为 true,并开始执行协程 Task。
(b) 等待 A:
协程首先进入 while (IsWaitingA) 循环,持续打印 “Waiting A”。
直到玩家按下 A 键,IsWaitingA 变为 false,然后打印 “IsWaitingA —— > OK”。
(c) 等待 B:
接下来,协程进入 while (IsWaitingB) 循环,开始一直打印 “Waiting B”。
直到玩家按下 B 键,IsWaitingB 变为 false,然后打印 “IsWaitingB —— > OK”。