IEnumerator 协程 全称协同程序 协成

本文深入解析Unity中的协程机制,包括协程的基本概念、启动与停止方法、常见yield表达式的使用场景及其内部工作原理,帮助读者理解如何有效地利用协程进行游戏逻辑的编写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

协成 返回参数的方法 


我们知道协成只能返回IEnumerator类型,但是委托可以预先设置好后续的事情

    //通过协成读取文件的内容
    public IEnumerator ReadFile(string path, Action<string> action)
    {
        WWW www = new WWW(path);
        yield return www;
        string data = www.text;
        action(data);
    }

    void Start()
    {
        StartCoroutine(ReadFile("www.youkuaiyun.com",
            _ =>
            {
                Debug.Log(_);
            }));
    }
输出:
//<!DOCTYPE html>
//<html>
//<head>
//    <meta charset="utf-8">
//......

 

表达式

yield return null;  //等1帧执行.暂停协同程序,下一帧再继续往下执行. 通知协程管理器,我到这个点要中断一下,下一帧从这个地方运行而已.

yield return 0;      //同yield return null;,数字改多大没用,都是等一帧

yield return 666; //同yield return null;,数字改多大没用,都是等一帧

yield break; //不在执行下面的语句,直接rerun

yield return asynaOperation; //等待异步操作执行完毕后执行

yield return StartCoroutine(coroutine); //等待子协程执行完毕后再执行

yield return  WWW();    在WWW下载完成之后……waits for a web request to complete (resumes as if WaitForSeconds or null)

yield return new WaitForEndOfFrame(); //等待帧结束,等待直到所有的摄像机和GUI被渲染完成后,在该帧显示在屏幕之前。用在while循环里减少死机

yield return new WaitForSeconds(0.3f);//等待0.3秒 , 一段指定的时间延迟之后继续执行,在所有的Update函数完成调用的那一帧之后注意:受Time.timeScale影响,当Time.timeScale = 0f 时,yield return new WaitForSecond(x) 将不会满足。

yield return new WaitForFixedUpdate(); // 所有脚本上的FixedUpdate函数已经执行调用之后持续

yield return new WaitUntil:将协同执行直到 当输入的参数(或者委托)为true的时候……  || yield return new WaitUntil(() => frame >= 10);

yield return new  WaitWhile:将协同执行直到 当输入的参数(或者委托)为false的时候…… || yield return new WaitWhile(() => frame < 10);

 

协程其实就是一个IEnumerator(迭代器),IEnumerator 接口有两个方法 Current 和 MoveNext() ,只有当MoveNext()返回 true时才可以访问 Current,否则会报错。迭代器方法运行到 yield return 语句时,会返回一个expression表达式并保留当前在代码中的位置。 当下次调用迭代器函数时执行从该位置重新启动。

Unity在每帧做的工作就是:调用 协程(迭代器)MoveNext() 方法,如果返回 true ,就从当前位置继续往下执行。

 

yield return 被会“翻译”为一个 IEnmerator 对象,这个对象实现的 MoveNext() 包含函数内所有 yield return 的处理

函数内有多少个 yield return 在对应的 MoveNext() 就会返回多少次 true (不包含嵌套)。

另外非常重要的一点的是:同一个函数内的其他代码(不是 yield return 语句)会被移到 MoveNext 中去,也就是说,每次 MoveNext 都会顺带执行同一个函数中 yield return 之前,之后 和两个 yield return 之间的代码。

 每次 执行协程 时,都会新建一个新(伪)线程去执行,第二次执行不会影响上一次的执行,

 结论是:协程适用于同一时间只运行一份函数的情况,如果同一时间运行多份同一个协程就会难以管理

协程不是线程,也不是异步执行的,是Unity每帧LateUpdate()之后都会去处理的函数

 

协程执行流程

1 如果 [gameObject激活] 并且 [脚本.enable=true ] 状态 下, StartCoroutine启动了协程 ,协程会立即运行到第一个 yield return 语句处,控制权交给外部

2. 等待Unity在下一帧(Frame)LateUpdate()之后

3.检查协程是否允许的条件 : 

脚本.enabled = false 协程会照常运行

a.检测 gameObject 是否处于激活(active) ,不激活不运行

b.检测 yield return 后面的表达式,如果满足就继续向下执行

 

 

IEnumerator 协程  全称协同程序

1.必须在MonoBehaviour或继承于MonoBehaviour的类中调用 yield coroutine。

2.StartCoroutine所在脚本物体必须是激活的.才能执行不报错.

 

MonoBehaviour.StartCoroutine方法即可开启一个协同程序,

 

StopCoroutine(methodName())//来终止一个协同程序,

StopAllCoroutines()//来终止所有可以终止的协同程序,

但这两个方法都只能终止该MonoBehaviour中的协同程序。

MonoBehaviour.enabled = false 协程会照常运行,gameObject.SetActive(false) 停止,即使在Inspector把  gameObject 激活还是没有继续执行

 

 

//yield return 被会“翻译”为一个 IEnmerator 对象

//yiled return 本质上和return作用一样,将当前函数返回。只不过下一次再调用这个函数,可以从yiled return的下一句开始执行,函数本身的变量也都会一直保存上一次调用的状态。

//yield return的作用是在执行到这行代码之后,将控制权立即交还给外部。yield return之后的代码会在外部代码再次调用MoveNext时才会执行,直到下一个yield return——或是迭代结束

yield return expression; //只有表达式完全执行结束才会继续执行后面的代码

 

 

<think>好的,我现在需要帮助用户解决关于Unity协程中使用yield return IEnumerator的问题。首先,我得回忆一下Unity协程的基本机制。根据引用中的内容,协程是基于C#的迭代器,通过IEnumerator状态机,分段执行代码。Unity每一帧都会检查并恢复协程的执行,具体取决于yield return返回的对象类型。 用户的问题集中在如何使用yield return后面接IEnumerator的情况。这意味着他们可能想要在一个协程中嵌套另一个协程,或者需要按顺序执行多个协程。我需要先确认这种用法的具体行为。 根据引用3,Unity维护一个活动协程队列,每次调用MoveNext()执行到下一个yield语句。当yield return另一个IEnumerator时,根据C#迭代器的特性,当前的协程会等待返回的IEnumerator完全执行完毕,再继续执行之后的代码。这类似于协程的嵌套调用,比如使用StartCoroutine来启动另一个协程,但这里的区别是直接通过yield return来等待另一个迭代器完。 接下来,我需要提供一个清晰的示例。例如,主协程A中yield return协程B的IEnumerator,这样A会暂停,直到B执行完毕。这在需要顺序执行多个协程时非常有用,比如先执行动画,再加载资源,最后播放声音。 同时,需要指出这种用法与StartCoroutine的区别。直接yield return另一个IEnumerator会阻塞当前协程直到子协程,而StartCoroutine则是并行执行,但根据引用3,协程并不会真正并行,而是在同一队列中按顺序处理。因此,使用yield return IEnumerator可以更直观地管理执行顺序,而无需显式启动子协程。 另外,需要注意语法正确性,确保示例代码中使用yield return正确返回IEnumerator,并说明每个步骤的作用。比如在示例中,协程A调用协程B,并在B完后继续执行A的剩余部分。 最后,总结这种用法的优势,比如代码结构更清晰,避免回调地狱,以及可能的应用场景,如任务链式执行。同时,提醒用户注意可能的陷阱,如无限循环或未正确终止的情况,确保协程能够正常结束。</think>在Unity协程中使用`yield return IEnumerator`可以实现协程的嵌套调用,通过等待另一个协程完全执行完毕后再继续当前协程。以下是具体用法和示例分析: --- ### 一、核心机制解析 1. **协程嵌套原理** 当协程A执行到`yield return IEnumerator`时(例如返回另一个协程B的迭代器),Unity会先完整执行协程B的所有代码,再继续执行协程A剩余的代码[^3]。 2. **执行顺序控制** 这种方式类似同步调用,但底层仍通过迭代器状态机的`MoveNext()`实现。Unity会依次处理嵌套协程的每一段代码块[^2]。 --- ### 二、典型使用场景 1. **链式任务执行** 需要按顺序执行多个协程(如先加载资源,再播放动画)。 2. **条件分支控制** 根据运行时条件动态选择执行不同的子协程。 --- ### 三、代码示例 ```csharp IEnumerator MainCoroutine() { Debug.Log("主协程开始"); yield return StartCoroutine(SubCoroutineA()); Debug.Log("主协程恢复,继续执行"); } IEnumerator SubCoroutineA() { Debug.Log("子协程A开始"); yield return new WaitForSeconds(1); Debug.Log("子协程A结束"); } ``` #### 执行结果: ``` 主协程开始 子协程A开始 (等待1秒) 子协程A结束 主协程恢复,继续执行 ``` --- ### 四、高级用法对比 | 方式 | 特点 | 适用场景 | |--------------------------|----------------------------------------------------------------------|------------------------| | `yield return StartCoroutine()` | 显式启动子协程,自动等待完 | 需要明确控制执行流程 | | 直接`yield return IEnumerator` | 隐式执行迭代器,无需通过StartCoroutine(但需注意生命周期管理) | 临时生迭代器对象时 | --- ### 五、注意事项 1. **生命周期问题** 若父协程被提前终止(通过`StopCoroutine`),嵌套的子协程也会自动终止[^3]。 2. **性能优化** 避免深层嵌套导致状态机复杂度增加,建议超过3层时重构为异步模式。 3. **异常处理** 子协程中的异常会直接中断整个协程链,建议使用`try-catch`包裹关键代码。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值