Menu
CoddyTech

协程中的循环

本课属于 Coddy Unity 学习旅程的“物理与游戏玩法”单元。第 25 课,共 71 课。

包含 yield return 的循环会跨越许多帧运行,因为每次循环都会暂停,然后才进入下一次循环。使用 WaitForSeconds,循环就会按节拍重复执行某些操作。这个警报灯会闪烁 3 次:

IEnumerator Flash()
{
    for (int i = 0; i < 3; i++)
    {
        lamp.enabled = true;
        yield return new WaitForSeconds(0.2f);
        lamp.enabled = false;
        yield return new WaitForSeconds(0.2f);
    }
}

使用 yield return null 时,循环会在每一帧执行一点操作,直到满足条件。这就是协程为某个对象制作动画的方式。这个气球的初始缩放值为 1,它会以每秒 0.5 的速度膨胀,直到缩放值达到 2,然后输出:

IEnumerator Inflate()
{
    while (transform.localScale.x < 2f)
    {
        transform.localScale += Vector3.one * 0.5f * Time.deltaTime;
        yield return null;
    }
    Debug.Log("Full");
}

Time.deltaTime 在这里的作用和 Update() 中一样:协程每帧恢复一次,而循环结束后才会执行循环后面的那一行。没有 yield 的话,整个循环会在一帧内运行完,气球会立刻膨胀完成。只要每次循环都会让出执行权,协程中的 while (true) 循环就没有问题;如果不让出执行权,它就永远不会把这一帧交还给 Unity,Unity 编辑器就会冻结。

challenge icon

挑战

简单

编写 Ride,让吊闸完成一次完整行程。

  1. 设置 Vector3 up = down + Vector3.up * height;。当 while (transform.position != up) 时,使用 Vector3.MoveTowards(transform.position, up, speed * Time.deltaTime) 移动,并执行 yield return null;。
  2. 记录 Open,然后执行 yield return new WaitForSeconds(1f);。
  3. 用相同的方式循环移动回 down,然后记录 Closed。

按下 开始,再按 Space:闸门升起、等待,然后关闭。接着点击 检查。

亲手试试

using System.Collections;
using UnityEngine;

public class Portcullis : MonoBehaviour
{
    public float speed = 1.5f;
    public float height = 3f;
    Vector3 down;

    void Start()
    {
        down = transform.position;
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            StartCoroutine(Ride());
        }
    }

    IEnumerator Ride()
    {
        // 以 speed 的速度上升 height 个单位,并记录 Open;停留 1 秒后下降,再记录 Closed
        yield return null;
    }
}

物理与游戏玩法中的所有课

自己练习: Unity 在线编辑器