Всем привет. Это перевод статьи из официального блога движка Unity. В ней пойдет речь о способе создания своих корутин, появившемся в версии 5.3.



Среди новых блестящих возможностей Unity 5.3 я обнаружил одну небольшую вещь, которая оказалась мне полезной, и, думаю, может пригодиться и вам. Это кастомные корутины, представленные классом CustomYieldInstruction. Благодаря ему, вы сможете очень просто создать свои собственные корутинные yield-операторы. Давайте рассмотрим это на живом примере.

Пример из реальной жизни — исправление ошибки


Недавно я изучал ошибку в элементе пользовательского интерфейса Dropdown, появившемся в Unity 5.2. При установке масштаба времени Time.timeScale в значение 0, Dropdown срабатывал только один раз, после чего он не появлялся снова, пока масштаб времени не устанавливался в какое-нибудь ненулевое значение.

После короткого поиска, мы обнаружили, что проблема возникает в методе Show:


Переменная m_Dropdown не равна null и это препятствует отображению Dropdown

После первого отображения m_Dropdown сворачивается и уничтожается. Да, он должен уничтожаться, но когда Time.timeScale равно нулю, этого не происходит.

Взгляните на метод уничтожения и попробуйте найти проблему:


Примечание от переводчика
В оригинале статьи (и здесь) в коде присутствует ошибка — вызов m_Items.Clear() должен быть после цикла for, а не внутри него. Спасибо пользователю Hruks за наводку.

Благодаря заголовку этой статьи можно догадаться, что проблема в WaitForSeconds. Этот класс использует масштабированное время. Это означает, что когда вы просите WaitForSeconds подождать 1 секунду при масштабе времени равному 0.5, то на самом деле пройдет 2 секунды (1 / 0.5 = 2). Если же масштаб времени равен 0, то придется ждать бесконечно (пока масштаб не станет ненулевым). Dropdown никогда не будет уничтожен после своего первого использования из-за использования нами класса WaitForSeconds.

Решение


Нам нужно реализовать задержку, используя реальное время. Наиболее элегантным подходом будет создание нового yield-оператора — класса WaitForSecondsRealtime. Конечно, если наши собственные разработчики не реализовали WaitForSeconds, используя масштабированное время, то мы должны сообщить им об этом. WaitForSecondsRealtime усилит этот посыл. Нам также нужно обновить документацию для WaitForSeconds, ведь мы нигде не имели ввиду масштабированное время.

Так я и обнаружил класс CustomYieldInstruction, добавленный недавно для создания новых yield-операторов.

Добавить новый оператор очень просто, и это будет решением нашей проблемы:


В любом кастомном yield-операторе нужно переопределить свойство keepWaiting. Если мы хотим, чтобы выполнение программы продолжилось, это свойство должно вернуть false.

Теперь наше исправление ошибки будет выглядеть вот так:


В нашем примере мы берем реальное время и сравниваем его при каждой проверке. Проще и быть не может… хотя, можно сделать и проще при помощи новых yield-операторов WaitUntil и WaitWhile. Используя их, мы можем передать делегат, который будет вызываться для нашей проверки.

Вот альтернативный способ решения проблемы (предположим, что мы просто хотим сделать пятисекундную задержку):


Итак, это была простая, но потенциально широкая возможность. Я считаю, что мораль здесь такова: нужно не забывать читать описания к выпускам версий, ведь в них можно найти новые полезные возможности! А если вам понравились кастомные корутины, взгляните также на UnityEvents — другую мою любимую возможность, которую вы могли пропустить.

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