用 Unity 构建模拟系统 – Coroutine(协程技术)

一、什么是协程?

协程是一种特殊的函数,其执行可以被暂停和恢复,适用于需要等待某个条件或时间的场景。在 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”。 

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注