【问题标题】:My HTML Canvas game is having performance issues我的 HTML Canvas 游戏存在性能问题
【发布时间】:2021-08-19 00:36:31
【问题描述】:

所以,我有一个在 Javascript 上运行的自然选择模拟,并且我使用 HTML Canvas 作为图形。问题是有数百个物体(生物),每个物体都在循环寻找食物和捕食者,每个物体都有几十个在繁殖时会发生突变的基因(变量)。好吧,图形非常简单(它们只是形状像圆形或椭圆形的彩色单元格),但整个循环嵌套正在扼杀性能。

我正在使用 animate() 函数,它通过 requestAnimationFrame(animate) 调用自身。好吧,在这个 animate() 函数中,除了每帧对屏幕上的每个元素进行整个绘制和重绘之外,我还循环生物数组以对它们中的每一个调用 Hunting() 和 update() 方法。并且有 2 个生物数组(草食动物和肉食动物),其中包含数百个对象,以及一个食物,可以包含数千个。这意味着我每帧循环通过三个数组,更不用说在生物方法内部发生的循环(例如,为了寻找食物,草食动物循环通过屏幕中的所有食物,计算与所有食物的距离,然后才寻找它)。

底线:每帧循环内循环内循环。所以我的问题是:有什么技巧可以提高性能吗?是否有任何工具可以分析代码并指出代码的哪些部分使用最多的内存?是否有(可能有)更有效的动画制作方法?

提前谢谢你!

【问题讨论】:

  • 正如@obe 建议的那样,代码分析是要走的路,最好的方法是 Chrome 开发工具。它能够逐帧告诉你问题等等!
  • 没有您的代码,我们无法为您提供改进其性能的建议。

标签: javascript performance canvas html5-canvas


【解决方案1】:

我建议使用requestAnimationFrame() 并在游戏循环的draw() 部分中,将所有单独的对象绘制到屏幕外的画布上,然后在可见画布上执行一个获取/放置图像。虽然这似乎对性能造成了影响,但是当您绘制许多对象时,这种获取/放置图像的开销实际上可以忽略不计。

Canvas 只是一个图像,根据我的经验,使用 Canvas 或图像在性能方面没有区别。

屏幕外或画布上没有什么不同,它们都会尽可能利用 GPU。

应避免使用context.getImageData()context.createImageData()context.putImageData() 进行实时渲染,它没有利用GPU,您对其进行的任何处理都将通过Javascript 在主内存中完成。虽然数据存储在类型化数组 Uint8ClampedArray 中,并且可以转换为任何类型的类型化数组,例如 Uint32Array,允许您使用一个变量而不是 4 个变量来处理单个像素。还有许多用于类型化数组的原生函数提供比标准 Javascript 数组更快的数组操作。

图像(包括画布作为图像)的限制因素是可用的 GPU RAM 量,当您超过可用 RAM 量时,浏览器将开始根据需要将图像交换到 GPU RAM 中,如果这样做会阻塞GPU 的渲染能力以及从主 RAM 到 GPU RAM 的传输与正常 RAM 访问相比很慢。发生这种情况时,您会立即看到帧速率下降。由于浏览器可以运行的平台种类繁多,而且无法知道机器的功能,因此在发布实时应用程序时应该小心。

如果您为高端台式机编写了具有高分辨率图像的游戏,那么它在平板电脑和低端笔记本电脑上的性能就不会很好。为了缓解这个问题,对图像进行下采样以匹配屏幕分辨率。在分辨率为 1/8 的设备上使用招聘背景图像会给硬件带来过度的压力。设备用于处理其屏幕的分辨率,超过此分辨率将对性能产生不必要的重大影响。在这里,您可以使用屏幕外画布以设备的原始分辨率渲染图像,然后转储原始员工图像。不会有质量损失,而是性能上的巨大提升,将无法播放的东西变成可播放的东西。这适用于所有图形资源。切勿以高于您正在使用的设备可以显示的分辨率存储和使用图像。

因为你可以用画布做各种各样的事情,所以找出最适合你的最好方法就是进行试验。监控帧速率并尝试不同的方法来解决手头的问题。如果帧速率提高了,您就找到了更好的处理方法,如果帧速率下降,则说明您使用了错误的方法。

【讨论】:

  • 这完全取决于绘制的内容。渲染几张位图可以比绘制几条路径更快,但是在单个路径中渲染多个形状会更快,甚至单个 putImageData + 像素生成也可以比很多位图绘制更快。没有一般规则。
  • 如果我的回答对您有帮助,请标记复选标记,以便对社区有所帮助。
【解决方案2】:

有什么技巧可以提高性能吗?

  1. 分析运行代码以识别真正/主要瓶颈并解决这些问题。

  2. 确定逻辑/算法的哪个特定部分花费的时间最多后,您可以考虑使用缓存等技术对其进行优化。例如,是否需要在每一帧中重新计算与所有食物的距离?也许每隔几秒钟重新计算一次就足够了?也许为每只动物保留一组 10 个相对接近的食物,而忽略其他数千种食物,并每隔几秒钟重新创建这个较小的数组?

有没有什么工具可以分析代码并指出哪些部分占用内存最多?

  1. 从您的描述看来,瓶颈似乎不是内存。更有可能是CPU。但两者都可以使用 Chrome 的开发工具进行分析。网上有很多资料。你可以从这里开始:https://www.html5rocks.com/en/mobile/profiling/

还有(可能有)更有效的动画制作方法吗?

  1. 对此我无能为力,但我建议首先确定实际的瓶颈是什么。对我来说,这听起来不像是动画本身。

【讨论】:

  • 感谢您的回答。不过,我有几个问题。我可以使用什么工具来“分析运行代码以识别真正/主要瓶颈并解决这些问题”?我只找到了可以判断整个代码是否繁重的工具,但是有没有办法分析代码的特定部分?此外,如果不是通过循环遍历所有生物,我无法找到另一种方法来计算最接近的食物。为了让我知道最近的 10 个(例如),我需要知道与所有人的距离,然后才能消除最远的距离......
  • (1) Chrome DevTools 的分析器可以显示在代码中不同位置花费的时间。它具有函数级别的粒度(IIRC 它可以显示函数被调用了多少次以及在其中花费了多少时间)。 (2) 您可能需要遍历所有这些,但是您是否需要在每一帧中遍历所有这些?例如如果您发现 10 种食物距离 20 像素以下,990 种食物距离 1000 像素,那么可能在 10 或 100 或 1000 帧后重新计算到这 990 种食物的距离,而不是下一个)。
猜你喜欢
  • 2011-06-16
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多