Страницы

среда, 4 декабря 2019 г.

Работа с корутинами в Unity. Часть 2. Coroutine vs Update


Теперь мы знаем, как создать корутину и как она работает. Следующая вещь, которую нужно обсудить – зачем вообще использовать корутины? Ведь все, что делается с помощью сопрограмм, может быть сделано с помощью метода Unity Update(). Однако природа корутин позволяет лучше выполнить определенные задачи. Такие задачи были бы более сложными и подверженными ошибкам в случае их реализации в методе обновления.

Прошу принимать вещи, которые будут дальше изложены, как руководство, чтобы помочь вам, а не правила. Я их нашел для себя, для облегчения своей работы. К тому же из любого правила бывают исключения, все зависит от конкретной задачи.

Когда использовать корутину

Корутина больше подходит, если вам нужно что-то изменить на основе условий, тогда как update() лучше работает с вводом. Например, логические значения при выполнении каких-то условий – перемещение персонажа, пока он не достигнет пункта назначения.

Это означает, что сопрограммы будут менее полезны, если они меняют поведение на основе ввода. Хороший пример – персонаж, который реагирует на действия игрока с клавиатурой, мышью, джойстиком или другим устройством ввода.

Подводя итог. Метод update лучше использовать для действий, которые нуждаются в повторении простых вещей или вводе. Корутина больше подходит для изменения состояний в зависимости от условий.

Дальше я приведу примеры, когда лучше использовать только корутины.
Начнем с простого примера. Допустим, мы хотим выполнить трехэтапную процедуру:
Подождать 1 секунду, затем вывести в дебаг-лог «Шаг 1».
Подождать 1 секунду, затем вывести в дебаг-лог «Шаг 2».
Подождать 1 секунду, затем вывести в дебаг-лог «Шаг 3».
Как бы вы сделали нечто подобное, используя метод обновления? Наверное, следует использовать логические переменные, отслеживающие, на каком шаге вы находитесь, в сочетании с переменной float для измерения прошедшего времени? Кажется немного раздражающим. Вот как можно сделать то же самое с помощью корутины:
public class ThreeStep : MonoBehaviour
{
   private IEnumerator Start()
   {
      yield return new WaitForSeconds(1f);
      Debug.Log(“Шаг 1”);
      yield return new WaitForSeconds(1f);
      Debug.Log(“Шаг 2”);
      yield return new WaitForSeconds(1f);
      Debug.Log(“Шаг 3”);
   }
}
Обратите внимание, что стартует IEnumerator, а не void. В этом случае Unity автоматически запустит код как сопрограмму. Можно использовать этот прием, если хотите, что бы сопрограмма начинала выполняться при старте сцены.
Код уже должен быть вам понятен. Мы ждем одну секунду, выводим сообщение и повторяем, пока не дойдем до конца. Можно написать это значительно короче, применив цикл:
private IEnumerator Start()
{
   for(int i = 1; i <= 3; i++)
   {
      yield return new WaitForSeconds(1f);
      Debug.Log(“Step ” + i);
   }
}
Это не только делает наш код лучше, но и показывает, как можно приостановить цикл в случае использования сопрограмм. В следующем примере у нас есть список/массив (list/array) светильников, и мы хотим, чтобы они выключались один за другим.
public class LightController : MonoBehaviour
{
   [SerializeField] private Light[] _lights;
   [SerializeField] private float _delay;
   private IEnumerator Start()
   {
      foreach(Light light in _lights)
      {
        light.enabled = false;
        yield return new WaitForSeconds(_delay);
      }
   }
}
Обратите внимание: SerializeField используется, когда мы хотим сделать доступ к полю из Инспектора, но не желаем делать это поле общедоступным в коде. Все, что мы делаем в этом примере,  - берем массив светильников, а затем выключаем их один за другим, ожидая х секунд, где х – это наше поле _delay. Если попробовать реализовать подобные действия с помощью метода обновления (update), то потребуется намного больше кода и времени для поиска ошибок.

Подводя итог. Корутины хороши, когда нужно изменять состояние в зависимости от условий. Есть и другие случаи, например, задержка выполнения, но лучшее применение сопрограмм – это изменение состояния.

По книге Lucas Faustino “Unity5 Coroutines”.
Другие части статьи
2 часть. Coroutine vs Update.