在收到事件后使用协程延迟。 延迟后,我应该将一个私有布尔'_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!!
}
答案 0 :(得分:2)
对于初学者,您的代码无法编译,您在bool
中未返回MyEventhandler
值。
但这并不是你的代码无法运行的原因,而是因为你在第一次调用后从未创建 new 协程,你总是尝试重新启动相同的协程实例。
你应该这样做:
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。
然后,coroutine = MyDelay();
用于创建对同一IEnumerator
方法的另一个实例的新引用,因此当您启动它时,您将从头开始并尝试重新启动实例这已经到了最后,根本不会做任何事情。
我会在_isActive = true;
的开头移动MyDelay()
,所以很清楚,通过只阅读该方法,该协程会做什么。
编辑:我将尝试解释为什么你需要创建一个新的引用来使它工作。
Unity中的 IEnumerator
只有两个可访问且有效的元素:MoveNext()
和Current
(Reset()
不起作用)。
这要归功于Unity MoveNext()
可以使协程工作。
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
,然后执行< / LI>
yield return new WaitForSeconds(1f);
被击中 - 现在Unity被指示在1秒后执行MoveNext()
(因此它会尝试通过使用{{1}检查时间差来使它适合两个Unity的回调之间})Time.deltaTime
被调用,MoveNext()
被执行。现在协程已经到了尽头,但Do Stuff #3
并没有好消失,如果你通过引用启动协程。因为引用保持不变,除非再次分配,所以即使您尝试使用IEnumerator
,Unity也会立即在该枚举器上执行StartCoroutine(reference)
,但在最后{{1}之后没有元素你点击了,所以它不会执行任何东西,因为没有什么可以执行。