Unity协程yield执行前为何运行后续语句?暂停逻辑异常
问题原因
核心问题是对Unity协程的执行逻辑存在误解:
- 调用
StartCoroutine()启动协程时,协程只会立刻执行到第一次yield return语句的位置,随后就会把控制权交回给调用方,不会阻塞调用方后续的主线程代码执行。 - 你当前代码的实际执行顺序为:
- 执行
DisplayTileFronts() - 启动
PauseGame协程:协程同步执行到Time.timeScale = 0f、计算等待结束时间、进入while循环,碰到yield return 0后暂停本次协程执行,控制权返回Start()方法 - 立刻执行
DisplayTileBacks(),完全没有等待3秒的暂停结束 - 后续每帧引擎会恢复协程执行判断时间,等满3秒后才会把
Time.timeScale设回1,完全不符合预期的暂停结束后再显示牌背的逻辑。
- 执行
修复方案
两种常用改法都可以实现预期效果,可根据代码结构选择:
方案1:将Start改为协程,等待PauseGame执行完成后再执行后续逻辑
Unity支持将生命周期函数Start的返回值设为IEnumerator,直接在Start里等待协程执行完毕即可,逻辑最直观:
IEnumerator Start() { // ... 保留原有其他逻辑 DisplayTileFronts(); // 等待PauseGame协程完整执行完(即3秒暂停结束)再往下走 yield return StartCoroutine(PauseGame(3f)); DisplayTileBacks(); } public IEnumerator PauseGame(float waitTime) { Time.timeScale = 0f; float waitEndTime = Time.realtimeSinceStartup + waitTime; while (Time.realtimeSinceStartup < waitEndTime) { yield return 0; } Time.timeScale = 1f; }
方案2:将暂停后执行的逻辑移入PauseGame协程末尾
不需要修改Start的返回值,直接把暂停结束后要跑的逻辑放到协程等待完成的位置即可:
void Start() { // ... 保留原有其他逻辑 DisplayTileFronts(); StartCoroutine(PauseGame(3f)); } public IEnumerator PauseGame(float waitTime) { Time.timeScale = 0f; float waitEndTime = Time.realtimeSinceStartup + waitTime; while (Time.realtimeSinceStartup < waitEndTime) { yield return 0; } Time.timeScale = 1f; // 3秒暂停结束后再执行显示牌背逻辑 DisplayTileBacks(); }
注:当前用
Time.realtimeSinceStartup做等待判断的写法是正确的,Time.timeScale = 0时所有受时间缩放影响的等待方法(比如WaitForSeconds)会完全失效,用真实时间计时才能正常等待。
内容的提问来源于stack exchange,提问作者Pezza
相关产品推荐
相关产品推荐

