База знаний ЯЮниор
  • C#
    • 🗃️Ссылочные и значимые типы в C# Ключевые слова ref, out, in Что нужно знать новичку
    • 📋Использование констант
    • 🔖Snippet или фрагмент кода
    • 📝Пустые строки
    • 🛡️Инкапсуляция
  • Unity
    • 🚶‍♂️Управление Параметрами Аниматора
    • ⚙️Динамическое изменение объектов
      • 🛠️Создание объектов
      • 🪛Изменение объектов
      • 🪚Добавление и изменение компонентов
      • 🔥Удаление объектов и компонентов
    • 🔊События
      • 🧬Параметризация
      • 🔗Совмещение событий
      • 📡Action и UnityAction
      • 🕹️UnityEvent
    • 🔌Подключение среды разработки к Unity
    • ⌚Корутины
      • 🪄Управление корутинами
      • ⏰Yield Instruction
      • 🕵️‍♂️Как устроены корутины?
  • Git и GitHub
    • 🗃️Git
    • 🗄️GitHub
    • 🖥️GitHub Desktop
Powered by GitBook
On this page
  • Что такое корутина?
  • Зачем нужны корутины?
  • Как можно упростить эту задачу?
  • Синтаксис корутин
  • Что еще нужно знать?

Was this helpful?

  1. Unity

Корутины

Автор: Дмитрий Прокопьев

Что такое корутина?

Слово "Корутина" (от англ. Coroutine) можно дословно перевести как "сопроцесс", то есть процесс, работающий параллельно основному.

Корутина это механизм Unity, который позволяет нам выполнять растянутые во времени действия удобным образом. По названию "Сопроцесс" можно ошибочно предположить, что корутины выполняются в отдельном процессе, но это не так. Они создают иллюзию параллельности для нашего удобства, но под капотом они выполняются в основном цикле обновления кадров - Update, с некоторыми исключениями.

С точки зрения производительности корутины чуть более затратны чем вызов Update, однако несущественно. По этой причине, если удобнее использовать корутину чем Update, - то она предпочтительна.

Зачем нужны корутины?

Допустим, мы хотим реализовать отсчет времени от 10 до 1 с помощью счетчика на экране. Реализация будет выглядеть так:

public class Timer : MonoBehaviour
{
    private float _elapsedTime = 0f;
    private int _counter = 10;
    
    private void Update()
    {
        _elapsedTime += Time.deltaTime;
        
        if (_elapsedTime >= 1)
        {
            _elapsedTime = 0;
            
            if (_counter > 0)
            {
                DisplayCountdown(_counter--);
            }
        }
    }

    private void DisplayCountdown(int countdown)
    {
        // отобразить на экране данное число
    }
}

Ужасно неудобно, так ведь? Создали два фактически лишних поля и выстроили двухэтажное условие в Update. А если у таких действий ещё и сложная логика, то вообще грустно. Здесь нас и спасут корутины!

Как можно упростить эту задачу?

В каком-нибудь счастливом сне мы могли бы написать такое:

private void MagicCountdown(int start = 10)
{
    for (int i = start; i > 0; i--)
    {
        DisplayCountdown(i);
        // магическим образом подождать одну секунду
        // и потом продолжить выполнение
    }
}

Насколько проще это было бы сделать! А секрет в том, что в корутинах это так и работает.

Синтаксис корутин

Вот так будет выглядеть готовая корутина, делающая то же самое:

private IEnumerator Countdown(int start = 10)
{
    for (int i = start; i > 0; i--)
    {
        DisplayCountdown(i);
        yield return new WaitForSeconds(1f);
    }
}

Можно увидеть, что корутина - это метод с возвращаемым типом IEnumerator. Это связано с технической особенностью реализации корутин.

Инструкция yield return позволяет указать задержку во времени на данной строке. Мы будто говорим исполняещему процессу "Выйди и зайди нормально" "Выйди, подожди сколько сказали, а потом продолжи". Когда исполнение корутины доходит до такой инструкции, оно временно прерывается и возобновляется после исполнения переданной инструкции.

Можно заметить, что на каждой итерации цикла мы заново создаем объект WaitForSeconds. Так как эти объекты одинаковые, нет смысла делать множество копий и засорять ими оперативную память. А также нам может потребоваться изменить время ожидания. Поэтому мы закешируем этот объект в целях оптимизации и выделим параметр:

private IEnumerator Countdown(float delay, int start = 10)
{
    var wait = new WaitForSeconds(delay);
    
    for (int i = start; i > 0; i--)
    {
        DisplayCountdown(i);
        yield return wait;
    }
}

Что еще нужно знать?

Важно. Когда исполнение корутины доходит до конца, она автоматически завершается - явно останавливать ее не нужно.

PreviousПодключение среды разработки к UnityNextУправление корутинами

Last updated 1 year ago

Was this helpful?

После инструкции yield return можно передать любой объект наследующий тип YieldInstruction. Класс-наследник можно реализовать самостоятельно, однако есть множество уже реализованных классов, подробнее про них можно прочитать .

Помимо написания корутин нужно также уметь ими управлять, о чем можно почитать .

Мы разобрались с синтаксисом, но чтобы пользоваться корутинами поистине эффективно, нужно понимать, как они работают! Об этом можно почитать .

⌚
здесь
здесь
здесь