程序设计基础
登录
< 返回教程列表

3.5 协程 Coroutine

知识介绍

协程 = 可以"暂停执行并在下一帧继续"的函数,用于"需要等待/分多帧执行"的逻辑。

using UnityEngine;
using System.Collections;   // 协程需要这个命名空间

public class CoroutineDemo : MonoBehaviour
{
    private void Start()
    {
        // 启动协程
        StartCoroutine(TestCoroutine());
    }

    // 协程方法:返回 IEnumerator
    IEnumerator TestCoroutine()
    {
        Debug.Log("协程开始");
        yield return null;                      // 暂停一帧
        Debug.Log("过了1帧");

        yield return new WaitForSeconds(2);     // 暂停2秒
        Debug.Log("又过了2秒");

        // 等待另一个协程结束
        yield return StartCoroutine(AnotherCoroutine());
        Debug.Log("另一个协程结束了,这个也结束");
    }

    IEnumerator AnotherCoroutine()
    {
        yield return new WaitForSeconds(1);
        Debug.Log("另一个协程:1秒");
    }

    // ============ 停止协程 ============
    private Coroutine _myCo;
    void StartAndStop()
    {
        _myCo = StartCoroutine(TestCoroutine());   // 保存引用
        StopCoroutine(_myCo);                      // 按引用停
        StopAllCoroutines();                       // 全停
    }
}

常用 yield 语句:

yield 写法 作用
yield return null; 等下一帧
yield return new WaitForSeconds(n); 等 n 秒
yield return new WaitForFixedUpdate(); 等下一次 FixedUpdate
yield return new WaitForEndOfFrame(); 等帧渲染结束
yield return StartCoroutine(Co()); 等另一个协程结束
yield break; 提前退出协程

例题

例题1: 倒计时 3、2、1 后爆炸(销毁 GameObject)。

IEnumerator CountdownBomb()
{
    for (int i = 3; i >= 1; i--)
    {
        Debug.Log($"爆炸倒计时:{i}");
        yield return new WaitForSeconds(1);
    }
    Debug.Log("Boom!");
    Destroy(gameObject);
}

例题2: 按打字机效果逐字输出字符串。

IEnumerator TypeText(string text, float interval = 0.1f)
{
    string result = "";
    foreach (char c in text)
    {
        result += c;
        Debug.Log(result);       // 实际项目可以给 UI Text.text 赋值
        yield return new WaitForSeconds(interval);
    }
}
// 调用:StartCoroutine(TypeText("Hello Unity!"));

例题3: 场景逐渐淡出(循环修改颜色)。

IEnumerator FadeOut(SpriteRenderer sr, float duration)
{
    float t = 0;
    Color original = sr.color;
    while (t < duration)
    {
        t += Time.deltaTime;
        float a = Mathf.Lerp(1, 0, t / duration);
        sr.color = new Color(original.r, original.g, original.b, a);
        yield return null;
    }
}

练习题

  1. 用协程写一个彩虹灯:Cube 的颜色 每秒 自动切换一种颜色(至少5种颜色循环)。

  2. 用协程做"闪现特效":OnCollisionEnter 触发时,把物体 Renderer.material.color 变成白色,等 0.1 秒再恢复原色(比如被击中闪白)。

  3. 做一个 DOTween 风格的协程方法:IEnumerator MoveTo(Transform t, Vector3 target, float duration),在 duration 秒内线性移动到 target 位置。

  4. 用协程实现一个"轻攻击 + 重攻击 + 连招":按 J 键启动一个协程,0.5秒内再按 J 触发第二击,0.5秒再按触发第三击,超过 0.5 秒没按就重置。