协程结束——实测

协程生命周期核心规则

协程是在 MonoBehaviour 实例 上运行的。它的生命周期依赖于该 MonoBehaviour 的 活动状态 以及 GameObject 的状态


物体设置

每个物体均挂载测试脚本


1. 正常结束 ✅ 会结束

  • 协程执行完最后一个 yield,方法自然返回 → 正常结束

  • 这是最常规的情况。


2. 所在 MonoBehaviour 被禁用 ❌ 不会结束

复制代码

一秒记录一次,第二秒暂停脚本,协程仍在运行

结果 :协程仍然会继续运行,不会结束。

⚠️ 重要enabled = false 只禁用 UpdateFixedUpdateLateUpdate 等生命周期方法,对协程没有影响 。协程独立于 enabled 状态运行。

一直在运行->update标识,后续就没有输出了


3. 所在 GameObject 被禁用 ❌ 不会结束?(需要分情况)

立即被禁用

没有继续了

重新开启

结果

GameObject 被禁用后 协程行为
立即被禁用 协程会暂停 ,但不会结束
稍后重新激活 协程从中断的地方继续执行????测试尚未恢复运行

⚠️ 关键点 :GameObject 被禁用后,协程不会运行 ,但协程状态被保留。重新激活后,协程会从上次 yield 的位置继续。


4. 所在 GameObject 被销毁 ✅ 会结束(被强制终止)

结果 :协程立即被终止,不会再执行任何代码。(第二秒终止,所有的都没有输出了)

Destroy(gameObject)Destroy(this) 被调用时,Unity 会清理该 MonoBehaviour 上所有正在运行的协程。


5. 场景切换 ✅ 会结束(除非特殊标记)

结果

场景切换方式 协程行为
SceneManager.LoadScene() 协程被终止
SceneManager.LoadSceneAsync() 协程被终止
加载时标记 DontDestroyOnLoad 的对象 ✅ 协程继续运行(因为对象没有被销毁)

⚠️ 场景切换时,未标记 DontDestroyOnLoad 的所有 GameObject 都会被销毁,因此其上的协程自然被终止。


6. 调用 StopCoroutine / StopAllCoroutines ✅ 会结束

结果 :协程立即被终止,不会继续执行。

注意:StopCoroutine(string methodName) 也可以停止,但推荐使用 Coroutine 对象的方式,避免重名问题。


完整总结表

场景 协程是否会结束 备注
1. 正常执行完毕 ✅ 结束 自然返回
2. MonoBehaviour 禁用 (enabled = false) 不会结束 协程独立于 enabled 运行
3. GameObject 禁用 (SetActive(false)) 但暂停
4. GameObject 销毁 (Destroy) 强制终止 协程被清理
5. 场景切换(未标记 DontDestroyOnLoad) 强制终止 对象被销毁
6. 调用 StopCoroutine / StopAllCoroutines 强制终止 手动停止

常见避坑建议

坑 1:以为禁用脚本就能停止协程

复制代码
enabled = false; // 协程还在跑!

正确做法 :需要停止协程时,显式调用 StopCoroutineStopAllCoroutines

坑 2:尚未切换开启的协程

  • 每次调用 Coroutinee(),都会创建一个全新的、未启动的协程实例
  • StopCoroutine 收到的,只是这个 "新创建的、没跑过的协程",而不是你之前 StartCoroutine 启动的那个
  • 结果就是:你停的是一个不存在的东西,原来的协程还在后台跑,完全不受影响

所以要接收,调用指定协程

代码

cs 复制代码
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class TestCooroutine : MonoBehaviour
{
    public string goName;
    public TestCooroutine testCooroutine;
    public Coroutine thisCoroutine;

    private void Start()
    {
        goName = gameObject.name;
        thisCoroutine = StartCoroutine(Coroutinee());
        testCooroutine = GetComponent<TestCooroutine>();
    }


    private void Update()
    {
        // Debug.Log("一直在运行奥");
        if (Input.GetKeyDown(KeyCode.Q))
        {
            testCooroutine.enabled = false;
        }
        else if (Input.GetKeyDown(KeyCode.W))
        {
            gameObject.SetActive(false); // 禁用整个 GameObject
        }
        else if (Input.GetKeyDown(KeyCode.E))
        {
            Destroy(gameObject); // 销毁 GameObject
        }
        else if (Input.GetKeyDown(KeyCode.R))
        {
            StopCoroutine(Coroutinee());
        }
        else if(Input.GetKeyDown(KeyCode.T))
        {
            SceneManager.LoadScene("Test2");
        }
        else if (Input.GetKeyDown(KeyCode.Y))
        {
            enabled = false;
        }
        else if (Input.GetKeyDown(KeyCode.U))
        {
             StopAllCoroutines();
        }
        else if (Input.GetKeyDown(KeyCode.I))
        {
            StopCoroutine(thisCoroutine);
        }
        
    }

    IEnumerator Coroutinee()
    {
        int circle = 15;
        while (circle > 0)
        {
            Debug.Log(goName + ":" + circle--);
            yield return new WaitForSeconds(1);
        }
        Debug.Log(goName+"已结束正常并退出");
    }
}
cs 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Test2 : MonoBehaviour
{
    private List<GameObject> _go;
    private void Start()
    {
        var test = FindObjectsOfType<TestCooroutine>().ToList();
        _go = test.Select(x => x.gameObject).ToList();
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.O))
        {
            for (int i = 0; i < _go.Count; i++)
            {
                _go[i].SetActive(true);
            }
            Debug.Log("恢复了");
        }
    }
}
相关推荐
ch.ju1 小时前
Java程序设计(第3版)第二章——函数的递归
java·开发语言
奔跑的蜗牛FelixChioa1 小时前
python异常处理机制详解
开发语言·python
其实防守也摸鱼1 小时前
ctfshow--Crypto(crypto1-14)解题步骤
java·开发语言·网络·安全·密码学·ctf·ctfshow
Komore3152 小时前
java 泛型
java·开发语言·泛型
Hemy082 小时前
tauri + rust 创建初始项目
开发语言·后端·rust
yqcoder2 小时前
JavaScript 浅拷贝:只复制“第一层”的艺术
开发语言·javascript·ecmascript
逻辑驱动的ken2 小时前
Java高频面试考点场景题26
java·开发语言·面试·职场和发展·求职招聘
yqcoder2 小时前
JavaScript 闭包:函数背后的“背包”
开发语言·javascript·ecmascript
阿里嘎多学长2 小时前
2026-05-08 GitHub 热点项目精选
开发语言·程序员·github·代码托管