我正在联合开发一款电子游戏,在某些时候我面临着一个很难解决的问题:
游戏在加载级别数据时冻结。
这个加载过程需要几秒钟的时间,我希望它会更长,因为我将不得不加载更大的景物(还没有完成)。
这个加载过程中的一些步骤不能在后台线程中运行,因为它们实例化了来自Unity的对象,而这些对象只能从其主线程执行,例如创建纹理、网格等。
我将把重点放在第二种方法,因为它似乎是正确的,但我对另一种方法持开放态度。
我可以使用什么方法或模式将长时间运行的操作拆分为较小的操作?
(希望你能明白,别告诉我。)
基本上,我的问题很简单,但很难修复,因为UI冻结了,因为在其中运行的任务需要比通常更长的访问时间;复杂的问题是如何在不重写整个任务的情况下重构它。我相信有一种更简单和同样有效的办法来解决这一问题。
由此产生了另外两个想法:
Dispatcher方法,我会在后台线程中运行整个过程,根据需要包装引擎调用,UI只会冻结一点;即使在AAA游戏中也是如此。发布于 2019-03-29 14:02:00
您需要将数据分配给Mesh。这种事必须发生。
没有办法可以绕过它。
Unity并不是线程安全的,所以它必须发生在主线程中。
没有办法可以绕过它。
因此,我们可以在这里建立的是,如果将任何数据分配给网格需要(太长)时间,恐怕这是不能改变的,它需要花费多长时间。然而,它可能正在读取和加载数据,这占用了处理时间的大部分时间。
你的两个想法,“启动协同线”和“将加载分成块”实际上是相同的。这是因为coroutine允许您在性能管理方面做的事情是:“好的,这对这个框架来说已经足够了,让我们在下一个中继续这样做”。
public IEnumerator ExecuteSomethingThatTakesLong()
{
for (int i = 0; i < 200; i++)
{
// A function that takes time to execute. Doing this 200 times
// in a row takes about a second, causing a lag.
TakeTime(10000);
// By waiting after each step, it will definitely take 200 frames
// to complete, but no noticable lag occurs.
yield return null;
}
}因此,为了从协同中获得您想要的东西,您将不得不“将加载分成块”。问题是,你必须找到一个很好的大小块。如果你发现一个块大小可以正常工作,那么对于性能较差的机器来说,这可能是太大了--而速度较慢的机器会结结巴巴的,因为每一个帧都有点太过了。
当然,这不是一个无法解决的问题;你可以留下一个足够好的空间等等。然而,分割一个3D模型文件并不是没有它自己的挑战,只是进一步复杂化了这一点。
如果您需要为WebGL平台构建,则没有线程,这是解决此问题的唯一角度。然而,从您的问题来看,您似乎在一个允许线程的平台上工作(几乎所有其他平台)。
如果您可以使用线程,那么在这里它们将是更容易的选择。他们说
你有问题了。你用线程来解决它。你现在有两个问题。
我也同意,但在这种情况下,线程似乎是更容易的选择。
幸运的是(或者更确切地说,是因为有人考虑了这个问题),Mesh使用了非常原始的数据;我们在这里讨论的是Vector3s和int[]s。Vector3是Unity的一部分,但它是一个例外,因为它是线程安全的。
为了获得最大的性能收益,我建议制作一个类似Mesh's数据的类。好吧,你需要的部分至少。这样,你就可以在另一个线程中填充所有你需要的数据。当你完成之后,你可以在主线程上一个一个地拷贝每个属性。
如果确实有必要,您还可以使用协同线进一步拆分数据分配(首先分配顶点,下一帧分配三角形,下一帧分配UVs.)。
https://softwareengineering.stackexchange.com/questions/389392
复制相似问题