【问题标题】:yield return new WaitForSeconds(2) destroys functionyield return new WaitForSeconds(2) 破坏函数
【发布时间】:2012-10-14 08:20:28
【问题描述】:

我决定做一个小记忆类游戏,用unity3d学习游戏开发。
游戏应在玩家点击卡片后等待 2 秒,然后再将卡片翻转回来。
yield return new WaitForSeconds(2)-statement 应该是完美的,但它的效果是没有执行函数的任何行。

这是我的代码:

这会构建卡片网格(带有按钮)并在卡片被点击时调用一个函数来翻转卡片。

Card card = grid[i, j];

if (GUILayout.Button(new GUIContent((Texture) Resources.Load(card.getImg()), ""), GUILayout.Width(cardWidth))) {
  Debug.Log("Call FlipCard");
  FlipCardFaceUp(card);
  Debug.Log("Returned from FlipCard");
}

这是翻转功能:

System.Collections.IEnumerable FlipCardFaceUp(Card card) {
    Debug.Log("This isn't shown in the console");
    card.isFaceUp = true;

    if (!cardsFlipped.Contains(card)) {
        cardsFlipped.Add(card);

        if (cardsFlipped.Count >= 2) {
            playerCanClick = false;
            //Waiting 2 seconds before the cards are flipped back or are removed
            yield return new WaitForSeconds(2);

            if (cardsFlipped[0].id == cardsFlipped[1].id) {
                cardsFlipped[0].isMatched = true;
                cardsFlipped[1].isMatched = true;
            } else {
                cardsFlipped[0].isFaceUp = false;
                cardsFlipped[1].isFaceUp = false;
            }

            cardsFlipped.Clear();
            playerCanClick = true;
        } 
    }
}

这是控制台输出,当我测试我的游戏并点击一张卡片时:

Call FlipCard
Returned from FlipCard

如果我删除了yield return 所需的东西,一切正常(除了玩家看不到第二张卡片,因为它会立即翻转回来)。

我的收益回报有什么问题?

【问题讨论】:

  • +1 我真的很喜欢戏剧性的标题。

标签: c# unity3d yield-return


【解决方案1】:

需要使用StartCoroutine启动协程:

StartCoroutine(FlipCardFaceUp(card));

正如 Marc Gravell 所说,需要枚举一个迭代器块来做任何事情,这就是 StartCoroutine 所做的(异步的,可能还有其他统一所需的东西)。 “异步”部分也是为什么在协程完成之前立即打印 "Returned from FlipCard" 的原因。

如果你想在打印"Return from FlipCard"之前等待你的协程完成,你也可以使用yield

Debug.Log("Call FlipCard");
yield return StartCoroutine(FlipCardFaceUp(card));
Debug.Log("Returned from FlipCard");

请注意,您不能在UpdateFixedUpdate 中使用yield

编辑:看到您正在尝试在OnGUI 方法中执行此操作,更好的方法可能是在此处使用Card 类型的变量,以便您记住要翻转哪张卡片。然后,在Update中,你可以检查那个变量,如果它说需要翻转卡片,你就可以启动协程。

【讨论】:

  • 有趣;所以这就是“统一期望将其作为协同程序消耗的另一种方式”
  • 如果我用StartCoroutine("FlipCardFaceUp", card)调用该方法,没有任何改变
  • @Lennart 你试过用yield return StartCoroutine(FlipCardFaceUp(card)) 来等待协程完成吗? (见编辑)
  • 如果我尝试这个,那么我的卡片就不会再创建了。也许重要的是要知道,该方法是由 OnGUI() 方法调用的。我应该发布我的所有代码吗?
  • @Lennart OnGUI 每帧可以调用多次,不应延迟。据我所知,你不能从那里启动协程。为什么不在另一个事件中处理呢?
【解决方案2】:

通过添加yield return,您已将其设为迭代器块。迭代器块仅在迭代时执行 - 它们展示了“延迟执行”。因此,要使其正常工作,您需要 consume 返回的枚举。最简单的可能是:

foreach(var obj in FlipCardFaceUp(card)) {}

但是,Unity 可能会以其他方式将其作为协同程序更新使用:确实如此;请参阅 Botz3000 的回答。在大多数 UI 中,阻塞更新代码是不好的(它会阻止绘制),但如果没有统一知识,我无法就正确的实现提出建议。据我所知,它可能希望您将 调用 代码转换为迭代器块:

// the following is COMPLETE GUESSWORK - I've never coded unity
// update: wrong: see Botz3000's answer, and `StartCoroutine`
Card card = grid[i, j];

if (GUILayout.Button(new GUIContent((Texture) Resources.Load(card.getImg()), ""), GUILayout.Width(cardWidth))) {
  foreach(var step in FlipCardFaceUp(card)) yield return step;
}

【讨论】:

    【解决方案3】:

    如果您通过StartCoroutine 调用您的方法,则只能使用yield return new WaitForSeconds(2)。您的第一个代码块将立即返回,但 Unity3d 将负责运行您的方法的其余部分(包括 2 秒的等待和之后的继续)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-19
      • 2018-11-09
      • 1970-01-01
      • 2016-06-15
      • 2018-12-18
      • 2018-03-05
      • 2014-08-19
      • 1970-01-01
      相关资源
      最近更新 更多