C# 协同程序和范围

C# 协同程序和范围,c#,unity3d,C#,Unity3d,在接收到事件后使用协同路由进行延迟。 延迟之后,我应该将私有布尔值“\u isActive”重置为false,但这永远不会发生。 这可能是由于范围问题吗 这是我的密码 using UnityEngine; using System.Collections; using System; IEnumerator coroutine; bool _isActive; void Awake() { _isActive = false; coroutine = MyDelay(); }

在接收到事件后使用协同路由进行延迟。 延迟之后,我应该将私有布尔值“\u 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);//可选-如下所示
coroutine=MyDelay();
启动程序(协同程序);
_isActive=true;
Debug.Log(“收到是事件”);
返回-激活;
}
stopcroutine(协同路由)
用于停止以前运行的协同程序,因此每次引发事件时,延迟将重置为2秒。如果您不想在延迟计时器结束之前重置它,即使引发了其他事件,也不要停止协程

然后,
coroutine=MyDelay()
用于创建对同一
IEnumerator
方法的另一个实例的新引用,这样当您启动它时,您就从一开始就开始启动它,并尝试重新启动一个已经到达终点的实例,而该实例根本不做任何事情

无论如何我都会移动
\u isActive=true
MyDelay()
的开头,因此,通过只读取该方法,可以清楚地看到该协同程序将执行什么操作

编辑:我将试着解释为什么需要创建一个新的引用来让它工作

Unity中的
IEnumerator只有两个可访问的工作元素:
MoveNext()
Current
Reset()
不工作)。 正是由于有了
MoveNext()
,Unity才能使协同程序正常工作

IEnumerator
的工作方式是这样的:它是一组只能按顺序访问的对象:第一次初始化时,
Current
指向第一个对象之前的元素,然后要访问下一个元素,需要调用
MoveNext()
,依此类推。在Unity之外,您可以使用
reset()
重置当前对象(使其返回到第一个元素),但正如我所说,这在Unity中不起作用

这就是在Unity中执行协程的方式:启动时,Unity执行所有代码,直到它到达
yield return
指令-这告诉Unity需要从哪个点重新开始执行剩余的代码。基本上,如果您有这样的代码:

IEnumerator MyCoroutine(){
//做事
收益返回空;
//做事2
返回新的等待秒(1f);
//做事
}
结果是:

  • Coroutine()
    start例程
    开始:此时,枚举数位于第一个元素之前
  • 第一个
    MoveNext()
    在枚举器上被调用,因此
    Current
    成为
    Do Stuff#1
    并被执行
  • yield return null
    -此时,Unity被指示中断代码的执行,直到通过一帧,执行将在下一次
    Update
    回调结束时开始
  • 在执行下一个
    Update()
    之后,Unity在
    MyCoroutine()
    上执行一个
    MoveNext()
    ,它将使当前的
    等于
    Do Stuff 2
    ,并将执行它
  • 返回新的WaitForSeconds(1f)被命中-现在Unity被指示在1秒后执行
    MoveNext()
    (因此它将通过使用
    time.deltaTime
    检查时间差,尝试在两次Unity回调之间进行匹配)
  • 1秒过后,调用
    MoveNext()
    ,执行
    Do Stuff#3

现在,协同程序已经结束,但是如果您通过引用启动协同程序,那么
IEnumerator
不会永远消失。因为除非再次赋值,否则引用将保持不变,所以即使您尝试使用
start例程(reference)
,Unity也会立即在该枚举器上执行
MoveNext()
,但在您点击的最后一个
Current
之后没有任何元素,所以它不会执行任何东西,因为没有什么可执行的。

对于初学者,您的代码无法编译,您没有在
MyEventhandler
中返回
bool

但这并不是代码不起作用的原因,因为在第一次调用后,您从未创建一个新的协同路由,您总是尝试重新启动同一个协同路由实例

您应该这样做:

private bool MyEventhandler(IEvent evt){
StopCoroutine(coroutine);//可选-如下所示
coroutine=MyDelay();
启动程序(协同程序);
_isActive=true;
Debug.Log(“收到是事件”);
返回-激活;
}
stopcroutine(协同路由)
用于停止以前运行的协同程序,因此每次引发事件时,延迟将重置为2秒。如果您不想在延迟计时器结束之前重置它,即使引发了其他事件,也不要停止协程

然后,
coroutine=MyDelay()
用于创建对同一
IEnumerator
方法的另一个实例的新引用,这样当您启动它时,您就从一开始就开始启动它,并尝试重新启动一个已经到达终点的实例,而该实例根本不做任何事情

无论如何我都会移动
\u isActive=true
MyDelay()
的开头,因此,通过只读取该方法,可以清楚地看到该协同程序将执行什么操作

编辑:我将试着解释为什么需要创建一个新的引用来让它工作

伊努梅拉