Для начала, ваш код не может быть скомпилирован, вы не возвращаете значение bool
в MyEventhandler
.
Но не потому, что ваш код не работает, а потому, что вы никогда не создаете новую сопрограмму после первого вызова, вы всегда пытаетесь перезапустить один и тот же экземпляр сопрограммы.
Вы должны сделать это:
private bool MyEventhandler(IEvent evt) {
StopCoroutine(coroutine); //OPTIONAL - read below
coroutine = MyDelay();
StartCoroutine(coroutine);
_isActive = true;
Debug.Log("Yes event received");
return _isActive;
}
StopCoroutine(coroutine);
используется для остановки ранее запущенной сопрограммы, поэтому при каждом возникновении события задержка сбрасывается до 2 секунд. Если вы не хотите сбрасывать таймер задержки до его окончания, даже если возникают другие события, не останавливайте сопрограмму.
Затем coroutine = MyDelay();
используется для создания новой ссылки на другой экземпляр того же метода IEnumerator
, так что, когда вы запускаете его, вы запускаете его с самого начала и пытаетесь перезапустить экземпляр, который уже нажал конец и ничего не будет делать.
Я бы в любом случае переместил _isActive = true;
в начале MyDelay()
, так что ясно, прочитав только этот метод, что будет делать эта сопрограмма.
РЕДАКТИРОВАТЬ: Я попытаюсь объяснить, почему вам нужно создать новую ссылку, чтобы заставить его работать.
IEnumerator
в Unity имеет только два доступных и рабочих элемента: MoveNext()
и Current
(Reset()
не работает).
Благодаря этому MoveNext()
Unity может заставить сопрограммы работать.
IEnumerator
работает следующим образом: это набор объектов, доступ к которым можно получить только последовательно: при первой инициализации Current
указывает на элемент перед первым объектом, затем на доступ к следующему элементу, вам нужно позвонить MoveNext()
и так далее. За пределами Unity вы можете сбросить текущий объект (вернув его к первому элементу) с помощью Reset()
, но, как я уже сказал, это не работает в Unity.
И вот как сопрограммы выполняются в Unity: при запуске Unity выполняет весь код до тех пор, пока не достигнет инструкции yield return
- это сообщает Unity, с какого момента необходимо возобновить выполнение оставшегося кода. В основном, если у вас есть такой код:
IEnumerator MyCoroutine() {
// Do stuff #1
yield return null;
//Do stuff #2
yield return new WaitForSeconds(1f);
//Do stuff #3
}
что происходит, это:
Coroutine()
запускается с StartCoroutine
: в этот момент счетчик располагается перед первым элементом
- Первый
MoveNext()
вызывается в перечислителе, поэтому Current
становится Do Stuff #1
и выполняется
yield return null
- в этот момент Unity получает команду прервать выполнение кода до тех пор, пока не будет передан кадр, выполнение начнется в конце следующего Update
обратного вызова
- После выполнения следующего
Update()
Unity делает MoveNext()
на MyCoroutine()
, что сделает Current
равным Do Stuff 2
, и выполнит его
yield return new WaitForSeconds(1f);
ударил - теперь Unity получает команду на выполнение MoveNext()
через 1 секунду (поэтому он попытается разместить его между двумя обратными вызовами Unity, проверив разницу во времени с помощью Time.deltaTime
)
- проходит 1 секунду, вызывается
MoveNext()
и выполняется Do Stuff #3
.
Теперь сопрограмма достигла конца, но IEnumerator
не пропал навсегда, если вы запустили сопрограмму посредством ссылки. Поскольку ссылка остается прежней, если только она не назначена снова, поэтому даже если вы попытаетесь использовать StartCoroutine(reference)
, Unity немедленно выполнит MoveNext()
на этом перечислителе, но после последнего Current
элементов не будет элементов, поэтому ничего не будет выполнено, потому что нечего выполнять.