【问题标题】:Display progress in a long loop in Unity3d在 Unity3d 中以长循环显示进度
【发布时间】:2015-05-24 13:28:35
【问题描述】:

我正在构建一个由数千个星系组成的太空游戏。现在,有一个函数可以生成这数千个系统。生成大约需要 5-10 秒,我希望有一个简单的进度条来更新用户的进度。

经过一番搜索,我决定使用协程,但是有一个小问题:当我调用该函数生成星系统时,调用该函数的代码继续运行,报告零星(因为他们没有'尚未生成)。

我觉得协程不是我的答案。基本上,我只是在寻找一种模拟 Application.DoEvents 来更新 GUI 的方法。

这是我的代码示例:

// Start generating thousands of systems
StartCoroutine(GalacticMap.GenerateRandomGalaxy());
// after the universe is generated...
Game.myGalaxy.StarSystems = GalacticMap.myGalaxy.StarSystems;
// report back the number of systems
print(String.Format("Generated {0} systems", Game.myGalaxy.StarSystems.Count));

GalacticMap.GenerateRandomGalaxy() 中,我像yield return new WaitForSeconds(0.1f); 一样让步,但是,效果不是我想要的:执行直接到print 语句,而生成仍在进行中。

那么我该怎么做呢?

编辑 1:

我已经编写了一个示例代码来说明我的问题。

调用者代码:

Debug.Log ("Start generating");
StartCoroutine(GenerateMeGalaxy());
Debug.Log ("Finish generating");

我调用的代码:

public static IEnumerator  GenerateMeGalaxy ()
{
    Debug.Log ("GenerateMeGalaxy start");
    int numberOfStars = 1000;

    for (int i=0;i<=numberOfStars;i++)
    {
        // generate galaxy

        // display progress bar on screen
        Debug.Monitor(String.Format("{0}% completed", ((i*100)/numberOfStars)),2);
        yield return new WaitForSeconds(0.001f);
    }
    Debug.Log ("GenerateMeGalaxy end");
}

在上面的代码中,Debug.Log 在屏幕上的新行上显示字符串,以便您可以读取以前记录的任何字符串。这是为了调试代码执行。 Debug.Monitor 在屏幕上有一个固定位置,会覆盖之前的字符串。这是我显示进度百分比的地方。运行这段代码后我看到的是:

Start generating
GenerateMeGalaxy start
Finish generating
GenerateMeGalaxy end

我想看到的是:

Start generating
GenerateMeGalaxy start
GenerateMeGalaxy end
Finish generating

...而且进度更新正在两者之间进行:

GenerateMeGalaxy start
Finish generating

【问题讨论】:

  • 不是很清楚你的问题是什么。可以细化吗?
  • 高级:我正在调用一个函数来生成大量的星系统。使用 1000 颗星执行该功能大约需要 5-10 秒。我有一个进度显示完成了多少生成通知用户。问题是,当我调用该函数时,我看不到进度像 5%...10%...15%... 等变化。屏幕上的所有内容都会冻结 510 秒,然后我只看到 100 % 函数完成时。在VB6中,这个问题会很容易解决......在更新进度条后放置DoEvents。 Unity 没有这个命令。

标签: loops unity3d progress-bar coroutine


【解决方案1】:

我认为您误解了 Unity 协程的工作原理。 yield return new WaitForSeconds(0.1f) 本质上说的是“去做其他事情,然后在 0.1 秒后回到我身边”。所以很自然,Unity 会继续做其他事情,包括打印语句。

你想要的是类似于以下模式的东西:

IEnumerator GenerateRandomGalaxy()
{
    int numSystems = 5000; // however many systems you want to generate
    foreach(int i = 0; i < numSystems; i++) 
    {
        // insert code here that generates system i

        // insert code here that updates the progress bar

        yield return null;
    }
    // put logic that prints out final number of systems generated here
}

它的作用是生成一个系统,更新状态栏,然后 -- 使用 yield return null 语句 -- 告诉 Unity 接管(以便它做其他事情,包括渲染更新的进度条)然后来尽快返回并继续循环。

最后,打印语句仅在循环完成后发生,如您所愿。

【讨论】:

  • 此方法不会更新 GUI 部分(进度条)。基本上,屏幕上的所有内容都会在例程完成后冻结并以 100% 的形式弹出
  • @George - 您需要添加逻辑来更新进度条,如图所示。如果没有看到你所有的代码,我很难说得更具体。
  • 更新进度的逻辑在那里,我可以看到它在做增量(在我的原始代码中)。问题是,当它进行增量时,调用函数的原始代码已经通过执行而不等待函数完成。我会看看我是否可以制作一个简单的例子并更新我的 OP
  • @George - “完成生成”立即打印的原因是我在回答中陈述的原因。您需要将其移至“打印此处生成的最终系统数量的放置逻辑”位置,否则它将在协程第一次产生时立即打印。
  • @George - 不知道你为什么要等待一小段时间来进行收益回报。应该没什么区别,因为时间几乎肯定少于一帧,但实际上你应该做 yield return null,它告诉 Unity 让控制权直到下一帧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-26
  • 2020-03-24
  • 2018-02-19
  • 2016-12-25
  • 2010-11-14
相关资源
最近更新 更多