Unity中如何让foreach循环暂停直至Coroutine协程执行完毕?
问题原因
当前写法无法生效的核心原因是:StartCoroutine属于非阻塞调用,调用后只会把传入的协程注册到Unity的协程调度队列,当前同步执行的foreach循环不会被挂起,会在同一帧内跑完所有列表元素的遍历,所有等待协程几乎同时启动,自然无法实现逐段等待的效果。
解决方案
最简洁可靠的实现方式是把整个脚本遍历逻辑本身做成协程,利用协程内部yield return的挂起特性,遇到等待指令时直接暂停整个遍历流程,等等待时长结束后自动恢复下一轮迭代。
修正后核心实现
首先把原来放在普通方法里的foreach循环移入专门的脚本执行协程,原来直接执行循环的位置替换为启动这个总协程即可:
// 原触发脚本执行的位置,替换为启动总协程 StartCoroutine(ExecuteScriptLines()); // 脚本执行总协程 IEnumerator ExecuteScriptLines() { Run = false; foreach (string line in ScriptLines) { if (line.Contains("Wait")) { int splitIndex = line.IndexOf(":"); int waitDuration = int.Parse(line.Substring(splitIndex + 1)); if (ShowDebugStatus) { Debug.Log($"Attempting to wait {waitDuration} seconds."); } // 直接在当前协程等待,等待完成前不会执行下一轮循环 yield return new WaitForSeconds(waitDuration); if (ShowDebugStatus) { Debug.Log("Wait finished."); } } else { // 此处编写非等待类脚本行的处理逻辑,比如显示对话、触发场景事件等 // 如果对应逻辑需要等待执行完成再走下一行,同样添加对应的yield return规则即可 } } // 所有脚本行执行完成后的收尾逻辑 Run = true; }
可选兼容写法
如果你需要保留单独定义的Wait()协程,只需要在调用StartCoroutine时前面添加yield return,就能让当前遍历协程等待嵌套的Wait协程执行完毕后再继续:
// 遍历协程内的Wait分支 if (line.Contains("Wait")) { Run = false; Index1 = line.IndexOf(":"); WaitTime = int.Parse(line.Substring(Index1 + 1)); if (ShowDebugStatus) { Debug.Log("Attempting to wait " + WaitTime + " seconds."); } // 等待嵌套协程执行完毕再继续 yield return StartCoroutine(Wait()); }
注意事项
- 协程的挂起是基于MonoBehaviour生命周期调度的,挂载脚本的物体需要保持激活状态,协程才能正常运行
- 不需要额外通过
Run标记手动控制循环阻塞,协程的yield本身就会自动中断后续逻辑执行,避免无意义的轮询开销 - 后续扩展其他脚本指令(比如播放动画、等待玩家输入)时,只需要在对应分支添加匹配的
yield return条件(比如等待动画结束、等待玩家点击),就能实现顺序执行的线性剧情脚本效果
内容的提问来源于stack exchange,提问作者CullisPlays
相关产品推荐
相关产品推荐

