【问题标题】:Clarification using closures in IEnumerator coroutines在 IEnumerator 协程中使用闭包的说明
【发布时间】:2018-12-07 22:51:44
【问题描述】:

我有 2 个 IEnumerator 协程,它们非常相似,应该将它们组合起来:

答:

IEnumerator CountDown_A() {
  timeLeft_A = totalTime_A;
  while (timeLeft_A > 0) {
    yield return new WaitForSeconds(1); 
    timeLeft_A--;
  }
}

乙:

IEnumerator CountDown_B() {
  timeLeft_B = totalTime_B;
  while (timeLeft_B > 0) {
    yield return new WaitForSeconds(1); 
    timeLeft_B--;
  }
}

唯一的两个区别是变量totalTime_A vs totalTime_BtimeLeft_A vs timeLeft_B。这些变量来自此函数的范围之外。

我在模块化这个协程时遇到的问题是timeLeft_AtimeLeft_B 的增量值需要应用到这个函数之外,所以我需要以某种方式传递对它们的引用。

用户“Kurt-Dekker”在this thread 中发布了一个很好的解决方案,但我无法将它应用到我的代码中。他说“使用闭包(函子)允许协程通过回调修改它”:

IEnumerator CountDown( System.Action<int> callback){
    ....
}

我认为应该这样称呼:

StartCoroutine ( CountDown( (i) => { timeLeft_A = i; } ) );
StartCoroutine ( CountDown( (i) => { timeLeft_B = i; } ) );

我不明白的是如何在 IEnumerator 内部引用/修改传入的 int 的实际值,如果我只需要使用回调函数的话。例如执行以下操作:

while(callback > 0){

或:

callback--;

任何帮助表示赞赏。

【问题讨论】:

  • 我不太明白你在问什么......你需要将参数传递给你的协程吗?
  • 好吧,经过第二次阅读,我现在明白了 :) 倒计时变量是在协程之外修改的,对吧?
  • 是的,我基本上需要通过引用将timeLeft_A 传递给CountDown_A()(值需要全局更改)。
  • 但我希望CountDown_A()CountDown_B() 具有相同的功能,所以也许CountDown()。所以全局变量不能在里面显式命名。
  • 好吧,没关系..我会尽力为你找到解决方案:)

标签: c# unity3d closures functor coroutine


【解决方案1】:

我认为这可能会回答您关于如何在协程中使用 System.Action&lt;float&gt; 的问题。

基本上,当您调用StartCoroutine 时,您会将计数器的最长时间作为普通参数和回调,此回调将浮点数作为参数(这里是 i)。

如果你在你的协程中调用callback(--timeLeft);,它会执行你传入的System.Action

这里会将timeLeft_AtimeLeft_B设置为对应协程的timeLeft变量。

public float timeLeft_A = 0f;
public float timeLeft_B = 0f;

public float totalTime_A = 15f;
public float totalTime_B = 20f;

// Start is called before the first frame update
void Start()
{
    StartCoroutine(Cooldown(totalTime_A, (i) =>
    {
        timeLeft_A = i;
    }));

    StartCoroutine(Cooldown(totalTime_B, (i) =>
    {
        timeLeft_B = i;
    }));
}

IEnumerator Cooldown(float totalTime, Action<float> callback)
{
    var timeLeft = totalTime;
    while (timeLeft > 0)
    {
        yield return new WaitForSeconds(1);
        callback(--timeLeft);
    }
}

【讨论】:

  • 非常感谢您抽出宝贵时间来做这件事!我很快就会试试看。
【解决方案2】:

根据 Antoine Thiry 的回答,将我的实现放在这里以供后代使用。

private static int totalTime_A = 45; // Num seconds
private int timeLeft_A = totalTime_A;
private static int totalTime_B = 30; // Num seconds
private int timeLeft_B = totalTime_B;

// Pass in totalTime separately from the callback (totalTime doesn't need to change)
IEnumerator CountDown(int totalTime, Action<int> callback){
  int timeLeft = totalTime; // Create new local var here to operate on it
  while (timeLeft > 0) {
    yield return new WaitForSeconds(1);
    callback(--timeLeft); // Then put the local var into callback after operating on it
  }
}

CountDown() 是这样调用的:

// timeLeft_A and timeLeft_B change globally
IEnumerator Countdown_A = CountDown(totalTime_A, (i) => { timeLeft_A = i; });
IEnumerator Countdown_B = CountDown(totalTime_B, (i) => { timeLeft_B = i; });
StartCoroutine(Countdown_A);
StopCoroutine(Countdown_A);
StartCoroutine(Countdown_B);
StopCoroutine(Countdown_B);

【讨论】:

    猜你喜欢
    • 2014-01-25
    • 2020-12-29
    • 2019-05-12
    • 1970-01-01
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多