用双缓冲改进Html5画布?

时间:2013-11-17 11:16:47

标签: javascript html5 double-buffering

我正在用javascript画布编写一个游戏,有时我会遇到延迟。我想这是因为我画了很多画布。

我的背景例如不是静态的,它从右向左移动,所以每次都要清除整个画布。而且我不是只用一种颜色清理,而是用一个移动游戏环的每个周期的图像清除。

我认为这是一项昂贵的操作,我在想是否有什么东西可以让这项操作更便宜,例如使用双缓冲来清除背景(不知道你是否可以使用双缓冲来清除背景? )。

或者我应该在整个游戏中使用双缓冲? (我不这么认为,因为我读过浏览器已经为你做了这个)

2 个答案:

答案 0 :(得分:2)

由于您经历了滞后'有时',并且它不是低帧速率问题,我宁愿将目光移向邪恶的垃圾收集器:无论何时触发,应用程序都会冻结到几毫秒,你就会得到帧错过 要注意这一点,您可以使用谷歌分析工具,在TimeLine / Memory /按下记录按钮:当使用的内存突然下降时,您可以看到GC发生了。
当使用这个工具时要小心,它会减慢应用程序的速度,并且会自行创建垃圾(!)......
此外,由于任何函数调用都会产生一些垃圾,因此您无法拥有完整的平坦内存行。

下面我展示了我在优化内存使用之前制作的简单游戏的图表,
每秒最多5个GC:

enter image description here

这里是内存优化之后相同游戏的图表:每秒有1个GC。由于我上面提到的限制,它实际上是我们可以得到的最好的,并且游戏没有帧丢失并且感觉更具响应性。

enter image description here

避免制造垃圾 - 永远不要创建对象,数组或函数 - 永远不要增大或缩小阵列尺寸 - 注意隐藏对象的创建:Function.bind或Array.splice是两个例子。

您还可以:
- 池(回收)您的对象 - 使用粒子引擎处理大量/短暂的对象。

如果您有兴趣,我可以使用池化lib(here)和粒子引擎(here)。

但也许首先要做的是寻找创建对象的位置,并只创建一次。由于js是单线程的,因此实际上可以将静态对象用于很多事情而没有任何风险。

只是一个小小的探索:

function complicatedComputation(parameters) {
   // ...
   var x=parameters.x, y = parameters.y, ... ...
}
// you can call creating an object each time :
 var res = complicatedComputation ( { x : this.x, y : this.y,  ... ...  } );

 //... or for instance define once a parameter object : 
 complicatedComputation.parameters = { x :0, y:0, ... ... };

 // then when you want to call :
 var params = complicatedComputation.parameters;
 params.x = this.x ; params.y = this.y; ... ...
 var res = complicatedComputation(params);

它的缺点是先前的调用参数仍然存在,所以如果你不这样做,你就不会被定义     设置它们,但是之前的值,所以你可能需要改变你的功能。
  但另一方面,如果你多次调用具有相似参数的函数,它就会非常方便。

快乐的记忆狩猎!

答案 1 :(得分:0)

双缓冲是一种减少闪烁的技术:在显示另一个缓冲区时绘制到一个缓冲区,然后在一次操作中将它们交换出来,这样用户就不会看到任何部分状态的绘图。 / p>

然而,它根本没有真正帮助解决性能问题,因为仍有相同数量的绘图。如果您没有闪烁问题,我不会尝试使用双缓冲,因为它需要更多内存,系统可能会通过类似或其他方式隐式阻止闪烁。

如果您认为绘制背景太贵,可以考虑以下几点:

  • 绘图时是否缩小背景图像?如果是这样,请创建一个缩小版本的版本并使用它来清除背景,从而降低每次迭代的绘图成本。

  • 记住“脏”区域,然后绘制被遮挡的背景部分。这将增加一些管理开销,但会减少需要显着触及的像素数量

  • 使背景成为canvas DOM元素的背景图像,并在每次迭代中将画布清除为透明度。如果画布非常大,你可以通过记住“脏”区域并清除它们来加快速度。

  • 你确定画背景是滞后的主要原因吗?当你只重画背景并且没有做太多其他事情时,你还有滞后吗?