前言

个人总结的一些Unity协程学习心得,如有不对请在评论区指出一起学习!感谢。

在Unity编程中谈到异步逻辑,可以考虑使用协程来实现。协程(Coroutine)在Unity中的主要作用就是把一个任务暂停(挂起),并在下一帧(或之后的某一时间点)继续。常见案例有网络请求、临时计时器、资源加载、打字机特效等。需要注意的是,协程不是线程,协程是在主线程中执行的。使用协程可以不用考虑同步和锁的问题。

1、C#迭代器

官方文档:遍历集合 - C# | Microsoft Learn

在了解并使用协程之前,我们可以先扩展一下关于C#迭代器的知识,方便我们理解什么是yield

迭代器方法或 get 访问器可对集合执行自定义迭代。 迭代器方法使用 yield return 语句返回元素,每次返回一个。 到达 yield return 语句时,会记住当前在代码中的位置。 下次调用迭代器函数时,将从该位置重新开始执行。迭代器方法或 get 访问器的返回类型可以是 IEnumerableIEnumerable<T>IEnumerator 或 IEnumerator<T>

在C#中,yield可以粗浅的理解为“产出”。用于实现迭代器,逐步产出序列中的元素

案例:写一个返回数字的迭代器方法

void Start()
{
    var numbers = GetNumbers();
    while (numbers.MoveNext())
    {
        Debug.Log($"t_Coroutine {numbers.Current}");
    }
}

IEnumerator GetNumbers()
{
    yield return 0;
    yield return 1;
    yield return 200;
}

 输出:

但是在Unity中,我们只用到了IEnumerator来创建协程方法。因此,我着重介绍一下IEnumerator接口。

1.1 IEnumerator

public interface IEnumerator
{
    object Current
    {
        get;
    }

    bool MoveNext();

    void Reset();
}

可以看到其实迭代器内部很简单。

Current是当前迭代器指向的对象;MoveNext()是移动指针指向下一个对象,如果是最后一个对象则返回false;Reset()是重置为最初状态。

2、协程基本语法

2.1 写一个简单的协程

协程开始时,会顺序执行yield return null;之前的代码,遇到yield return 会被挂起(暂停),等待指定时间后,从被挂起的地方继续往下执行。

using System.Collections;
using UnityEngine;

public class CoroutineExample : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(MyCoroutine());
    }

    IEnumerator MyCoroutine()
    {
        // 开启协程就会执行的逻辑
        Debug.Log("t_Coroutine Start Coroutine");
        yield return null;  //在这里被暂停,暂停1帧
        //挂起并恢复之后的逻辑
        Debug.Log("t_Coroutine Wait One Frame After");
        yield return new WaitForSeconds(2); //在这里被暂停,暂停2秒
        Debug.Log("t_Coroutine Wait Two Seconds After");
        //协程结束
    }
}

输出:

 

2.2 yield return的不同用法

2.2.1 yield return null 与 yield return 1

在Unity协程中,yield return null; 和 yield return 1; 实际上是等效的,二者都会暂停协程的执行并在下一帧继续执行。即等待一帧

之所以等效,是因为yield return会返回一个值给Unity的协程调度器,这个值用于决定协程何时继续。null和任意整数(例如1)都会导致协程在下一帧恢复执行。

2.2.2 yield break

立即停止协程

案例:可以看到Break After并没有被打印出来,在此之前协程就停止了

using System.Collections;
using UnityEngine;

public class CoroutineExample : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(MyCoroutineBreak());
    }

    IEnumerator MyCoroutineBreak()
    {
        Debug.Log("t_Coroutine Start MyCoroutineBreak");
        yield return null;  //在这里被暂停,暂停1帧
        Debug.Log("t_Coroutine Wait Two Seconds After");
        yield break;//协程结束
        Debug.Log("t_Coroutine Break After");
    }
}

输出: 

2.2.3 yield return StartCoroutine(OtherCoroutine())

协程是可以嵌套的,可以使用yield return StartCoroutine(OtherCoroutine()),等待OtherCoroutine协程方法执行完毕后,再继续往下执行

案例:

void Start()
{
    Debug.Log("t_Coroutine Start1");
    StartCoroutine(TestCoroutine());
    Debug.Log("t_Coroutine Start2");
}

IEnumerator TestCoroutine()
{
    Debug.Log("t_Coroutine test1");
    yield return StartCoroutine(LoadCoroutine());
    Debug.Log("t_Coroutine test2");
}

IEnumerator LoadCoroutine()
{
    Debug.Log("t_Coroutine load 1");
    yield return null;
    Debug.Log("t_Coroutine load 2");
}

输出:

 

 2.2.4 其他用法

yield return new WaitForEndOfFrame();//等待帧结束

yield return new WaitForSeconds(1f);//等待1秒;

yield return WebRequest();//等待到网络请求结束返回结果的时候;

yield return new WaitUntil()//等待到结果返回为true的时候

yield return new WaitWhile()//等待到结果返回为false的时候

2.3 开启 / 停止协程

2.3.1 直接开启一个协程

无法控制暂停,直接调用协程方法开启

StartCoroutine(MyCoroutine());

2.3.2 用变量控制协程

private Coroutine myCoroutine;
myCoroutine = StartCoroutine(MyCoroutine());//开启协程
StopCoroutine(myCoroutine);//停止协程

2.3.3 用协程方法名控制协程

StartCoroutine("MyCoroutine");//开启协程
StopCoroutine("MyCoroutine");//停止协程

2.3.4 停止所有正在运行的协程

会停止该对象上所有正在运行的协程,慎用!

当一个游戏对象(GameObject)把Active设置为false,即SetActive(false),也会停止该对象上附加的协程。

调用Destroy(GameObject)时,Unity会调用OnDisable(),处理并停止协程。在这一帧结束时,会调用OnDestroy()。

StopAllCoroutines();

3、学习参考博客

官方文档:Unity - Manual: Coroutines

通俗易懂博客(建议先看这个,很好理解):Unity C#中协程/携程Coroutine简单易懂详解-CSDN博客

更进一步理解:Unity StartCoroutine - 简书

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部