[英]Coroutines and scope
收到事件后,使用协程程序进行延迟。 延迟之后,我应该将私有布尔值'_isActive'重置为false,但这永远不会发生。 这可能是由于范围问题吗?
这是我的代码
using UnityEngine;
using System.Collections;
using System;
IEnumerator coroutine;
bool _isActive;
void Awake()
{
_isActive = false;
coroutine = MyDelay();
}
private bool MyEventhandler(IEvent evt)
{
StartCoroutine(coroutine);
_isActive = true;
Debug.Log("Yes event received");
}
IEnumerator MyDelay()
{
yield return new WaitForSeconds(2.0f);
Debug.Log("Yes delay complete");
_isActive = false;//private class variable _isActive does not get reset to false
}
void Update(){
Debug.Log(" _isActive = " + _isActive);//_isActive gets set to true but never gets reset to false!!
}
对于初学者,您的代码无法编译,您不会在MyEventhandler
返回bool
值。
但这不是您的代码无法正常工作的原因,这是因为您从未在第一次调用后创建新的协程,而是总是尝试重新启动相同的协程实例。
你应该做这个:
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()
的开头,因此很明显,通过仅读取该方法,协程将执行的操作。
编辑:我将尝试解释为什么您需要创建一个新的引用才能使其正常工作。
Unity中的IEnumerator
只有两个可访问且有效的元素: MoveNext()
和Current
( Reset()
不起作用)。 多亏了MoveNext()
,Unity才能使协程正常工作。
IEnumerator
工作方式如下:它是对象的集合,只能按顺序访问:第一次初始化时, Current
指向第一个对象之前的元素,然后访问下一个元素,您需要调用MoveNext()
, 等等。 在Unity之外,您可以使用Reset()
重置当前对象(使其返回第一个元素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()
第一个MoveNext()
,因此Current
成为Do Stuff #1
并被执行 yield return null
这时,指示Unity中断代码的执行,直到通过一个帧为止,该执行将在下一个Update
回调的末尾开始 Update()
之后,Unity在MyCoroutine()
上执行MoveNext()
MyCoroutine()
,这将使Current
等于Do Stuff 2
并执行 yield return new WaitForSeconds(1f);
被击中-现在指示Unity在1秒后执行MoveNext()
(因此它将通过使用Time.deltaTime
检查时间差来尝试使其适合两个Unity回调之间的时间) MoveNext()
,并Do Stuff #3
。 现在协程已经结束,但如果您通过引用启动协程,则IEnumerator
不会永远消失。 因为除非重新分配引用,否则引用将保持不变,因此即使您尝试使用StartCoroutine(reference)
,Unity也会立即在该枚举器上执行MoveNext()
,但是在您击中的最后一个Current
之后没有元素,因此它什么也不会执行,因为什么都没有执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.