← Назад к вопросам

Какие знаешь yield инструкции?

2.2 Middle🔥 192 комментариев
#C# и ООП#Unity Core#Асинхронность и многопоточность

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Yield инструкции в C# для Unity

В Unity разработке yield инструкции — это фундаментальный механизм корутин, позволяющий приостанавливать выполнение функции на одном или нескольких кадрах без блокировки основного потока. Это мощный инструмент для управления временем, асинхронными операциями и последовательностями действий.

Основные типы yield инструкций

1. Yield return null и yield break

// yield return null - приостановка на один кадр
IEnumerator UpdateEveryFrame()
{
    while (true)
    {
        Debug.Log("Выполняется каждый кадр");
        yield return null; // Ждем следующий кадр
    }
}

// yield break - немедленное завершение корутины
IEnumerator ProcessWithCondition()
{
    if (!isValid)
    {
        Debug.Log("Условие не выполнено, завершаем корутину");
        yield break; // Немедленный выход
    }
    // Дальнейшая логика...
}

2. WaitForSeconds и WaitForSecondsRealtime

IEnumerator DelayedAction()
{
    Debug.Log("Начало ожидания");
    
    // Ожидание с использованием масштабированного времени (зависит от Time.timeScale)
    yield return new WaitForSeconds(2.5f);
    Debug.Log("Прошло 2.5 секунды (масштабированное время)");
    
    // Ожидание с использованием реального времени (не зависит от Time.timeScale)
    yield return new WaitForSecondsRealtime(1f);
    Debug.Log("Прошла 1 секунда реального времени");
}

3. WaitForEndOfFrame и WaitForFixedUpdate

IEnumerator FrameOperations()
{
    // WaitForEndOfFrame - выполнение в конце рендеринга кадра
    yield return new WaitForEndOfFrame();
    CaptureScreenshot(); // Идеально для скриншотов
    
    // WaitForFixedUpdate - выполнение перед физическим обновлением
    yield return new WaitForFixedUpdate();
    ApplyPhysicsForce(); // Безопасные операции с физикой
}

4. WaitUntil и WaitWhile (условные ожидания)

IEnumerator WaitForCondition()
{
    // Ожидание, пока условие не станет истинным
    Debug.Log("Ждем, пока игрок не нажмет Space...");
    yield return new WaitUntil(() => Input.GetKeyDown(KeyCode.Space));
    Debug.Log("Space нажата!");
    
    // Ожидание, пока условие истинно
    yield return new WaitWhile(() => player.IsMoving);
    Debug.Log("Игрок остановился");
}

5. Custom Yield Instructions (пользовательские инструкции)

// Создание собственной инструкции ожидания
public class WaitForCustomEvent : CustomYieldInstruction
{
    private bool isEventTriggered = false;
    
    public override bool keepWaiting => !isEventTriggered;
    
    public void TriggerEvent()
    {
        isEventTriggered = true;
    }
}

// Использование в корутине
IEnumerator WaitForCustomTrigger()
{
    var customWait = new WaitForCustomEvent();
    StartCoroutine(TriggerLater(customWait));
    
    yield return customWait; // Ждем, пока событие не сработает
    Debug.Log("Событие сработало!");
}

6. AsyncOperation ожидания (для асинхронных операций)

IEnumerator LoadSceneAsync()
{
    AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Level2");
    
    // Ожидание завершения асинхронной загрузки
    yield return asyncLoad;
    
    // Или с прогрессом
    while (!asyncLoad.isDone)
    {
        float progress = Mathf.Clamp01(asyncLoad.progress / 0.9f);
        Debug.Log($"Прогресс загрузки: {progress * 100}%");
        yield return null;
    }
}

Практические примеры использования

// Комбинированный пример
IEnumerator ComplexSequence()
{
    // Этап 1: Начальная задержка
    yield return new WaitForSeconds(1f);
    
    // Этап 2: Ожидание ввода
    Debug.Log("Нажмите Enter для продолжения");
    yield return new WaitUntil(() => Input.GetKeyDown(KeyCode.Return));
    
    // Этап 3: Анимация в течение нескольких кадров
    for (int i = 0; i < 60; i++) // Примерно 1 секунда при 60 FPS
    {
        objectToAnimate.transform.Rotate(0, 6f, 0);
        yield return null; // Один кадр анимации
    }
    
    // Этап 4: Ожидание загрузки ресурсов
    ResourceRequest request = Resources.LoadAsync<Texture>("Textures/MyTexture");
    yield return request;
    
    // Этап 5: Финальная логика
    Debug.Log("Последовательность завершена");
}

Ключевые особенности и лучшие практики

  • Производительность: Каждая активная корутина потребляет немного памяти (примерно 1 КБ на экземпляр)
  • Управление: Всегда храните ссылку на Coroutine для возможности остановки через StopCoroutine()
  • Ошибки: Исключения в корутинах не приводят к падению всего приложения, но прерывают выполнение конкретной корутины
  • Вложенность: Корутины могут запускать другие корутины через yield return StartCoroutine(OtherRoutine())

Отличия в разных версиях Unity

В более новых версиях Unity (после 2017.3) появилась поддержка async/await паттерна, который может использоваться как альтернатива корутинам для многих асинхронных операций, особенно при работе с .NET 4.x Runtime. Однако корутины остаются предпочтительным выбором для:

  • Операций, привязанных к кадрам
  • Последовательностей, зависящих от времени игры
  • Совместимости с Unity API, который не поддерживает async/await

Понимание всех доступных yield инструкций и их правильное применение — ключ к созданию отзывчивых, эффективных и читаемых асинхронных операций в Unity.

Какие знаешь yield инструкции? | PrepBro