App/game 在协程运行时完全冻结

App/game freezes completely while coroutine runs

我的 Android ARCore Unity app/game 在协程运行时冻结,然后在协程完成后恢复。协程位于附加到游戏对象的脚本中,协程在 Start() 函数中调用。我已经尝试将 yield return null; 插入协程的更多部分,这减少了暂停时间,但增加了更多暂停,导致对象实例化后一两秒的游戏玩法非常不稳定(基本上不存在)。发生这种情况可能是因为 ARCore 不支持多线程渲染吗?如果是这种情况(或不是),我该如何解决这个问题,以便我的协程在实例化对象后运行(我猜 'in the background'),因此它不会影响游戏玩法 FPS?

这是我的代码:

void Start() 
{
    StartCoroutine(MyCoroutine());
}

IEnumerator MyCoroutine ()
{
    yield return null;
    Transform[] allChildren = GetComponentsInChildren<Transform>();
    foreach (Transform child in allChildren)
    {
        if (child.gameObject.GetComponent<MeshFilter>())
        {
            if (!child.gameObject.GetComponent<MeshCollider>())
            {
                child.gameObject.AddComponent<MeshCollider>();
            }
        }
        child.gameObject.tag = "CenterObject";
    }
}

这是因为你在协程中陷入了循环。您需要将 yield 移动到循环内部:

IEnumerator MyCoroutine ()
{
    Transform[] allChildren = GetComponentsInChildren<Transform>();
    foreach (Transform child in allChildren)
    {
        if (child.gameObject.GetComponent<MeshFilter>())
        {
            if (!child.gameObject.GetComponent<MeshCollider>())
            {
                child.gameObject.AddComponent<MeshCollider>();
            }
        }
        child.gameObject.tag = "CenterObject";
        yield return null;
    }
}

即便如此,如果这是您循环访问的大量子项,则可能只是性能问题。

协程在构造它们时似乎有开销,如下所述:https://forum.unity.com/threads/startcoroutine-performance-cost.233623/

鉴于您要实例化对象,我会建议这些路径:

  • 将协程更改为简单的函数调用,因为您似乎不需要在循环迭代之间有任何延迟,这是在 Unity 中使用协程的主要想法。您还添加了碰撞器并期望游戏继续进行,如果您需要注册碰撞,这可能会导致意外行为。
  • 如果可能,实例化预先连接了碰撞器的预制件。
  • 使用对象池,您可以在游戏开始前创建对象并在需要时激活它们,并在销毁它们时禁用它们(如有必要)。

除了修复协程的答案外:

协程并不是真正的多线程!这就是为什么如果协程中有一个很长的任务,你的应用程序就会冻结。

协程的 yield return 使它 easy/lazy 可以做一个快速动画或类似的东西,因为协程有点 "remember" 他们离开的地方并从这一点继续(到用简单的话来说)所以你可以 运行 显然 "parallel" 很多事情。但它仍然在同一个线程中 运行s 所以实际上它似乎只是并行执行,因为一切都在两个帧之间执行。

如果您确实有一项耗时的任务想在另一个线程中完成,那么请查看 async await,这是自 Unity 2017 以来 Unity 真正的多线程。

然而 Unity 不是 线程保存意味着大多数 API 只能在主线程中使用...