Version: 2021.1
Функции событий
Пространства имён

Coroutines

Когда вы вызываете функцию, она должна полностью выполниться, прежде чем вернуть какое-то значение. Фактически, это означает, что любые действия, происходящие в функции, должны выполниться в течение одного кадра; вызовы функций не пригодны для, скажем, процедурной анимации или любой другой временной последовательности. В качестве примера мы рассмотрим задачу по уменьшению прозрачности объекта до его полного исчезновения.

void Fade()
{
    Color c = renderer.material.color;
    for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
    {
        c.a = alpha;
        renderer.material.color = c;
    }
}

Как можно заметить, функция Fade не имеет визуального эффекта, который мы хотели получить. Для скрытия объекта нам нужно было постепенно уменьшить прозрачность, а значит иметь некоторую задержку для того, чтобы были отображены промежуточные значения параметра. Однако функция выполняется в полном объеме, за одно обновление кадра. Промежуточные значения, увы, не будут видны и объект исчезнет мгновенно.

С подобными ситуациями можно справиться, добавив в функцию Update код, изменяющий прозрачность кадр за кадром. Однако для подобных задач зачастую удобнее использовать корутины.

A coroutine is like a function that has the ability to pause execution and return control to Unity but then to continue where it left off on the following frame. In C#, a coroutine is declared like this:

IEnumerator Fade()
{
    Color c = renderer.material.color;
    for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
    {
        c.a = alpha;
        renderer.material.color = c;
        yield return null;
    }
}

It is essentially a function declared with a return type of IEnumerator and with the yield return statement included somewhere in the body. The yield return null line is the point at which execution will pause and be resumed the following frame. To set a coroutine running, you need to use the StartCoroutine function:

void Update()
{
    if (Input.GetKeyDown("f"))
    {
        StartCoroutine(Fade());
    }
}

Можно заметить, что счетчик цикла в функции Fade сохраняет правильное значение во время работы корутины. Фактически, любая переменная или параметр будут корректно сохранены между вызовами оператора yield.

By default, a coroutine is resumed on the frame after it yields but it is also possible to introduce a time delay using WaitForSeconds:

IEnumerator Fade()
{
    Color c = renderer.material.color;
    for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
    {
        c.a = alpha;
        renderer.material.color = c;
        yield return new WaitForSeconds(.1f);
    }
}

This can be used as a way to spread an effect over a period of time, but it is also a useful optimization. Many tasks in a game need to be carried out periodically and the most obvious way to do this is to include them in the Update function. However, this function will typically be called many times per second. When a task doesn’t need to be repeated quite so frequently, you can put it in a coroutine to get an update regularly but not every single frame. An example of this might be an alarm that warns the player if an enemy is nearby. The code might look something like this:

bool ProximityCheck()
{
    for (int i = 0; i < enemies.Length; i++)
    {
        if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance) {
                return true;
        }
    }

    return false;
}

If there are a lot of enemies then calling this function every frame might introduce a significant overhead. However, you could use a coroutine to call it every tenth of a second:

IEnumerator DoCheck()
{
    for(;;)
    {
        if (ProximityCheck())
        {
            // Perform some action here
        }
        yield return new WaitForSeconds(.1f);
    }
}

Это значительно уменьшит число проверок, но не окажет заметного влияния на игровой процесс.

Note: You can stop a Coroutine with StopCoroutine and StopAllCoroutines. The coroutine also stops when the GameObject it is attached to is disabled with SetActive(false). Take note that the coroutine does not continue if the GameObject is re-enabled. Calling Destroy(example) (where example is a MonoBehaviour instance) immediately triggers OnDisable and the coroutine is processed, effectively stopping it. Finally, OnDestroy is invoked at the end of the frame.

Coroutines are not stopped when disabling a MonoBehaviour by setting enabled to false on a MonoBehaviour instance.

Функции событий
Пространства имён
Copyright © 2023 Unity Technologies
优美缔软件(上海)有限公司 版权所有
"Unity"、Unity 徽标及其他 Unity 商标是 Unity Technologies 或其附属机构在美国及其他地区的商标或注册商标。其他名称或品牌是其各自所有者的商标。
公安部备案号:
31010902002961