HTML5 Canvas中的大型2D世界渲染

时间:2014-08-09 04:10:09

标签: javascript html5 canvas html5-canvas

我有一个由随机生成的块组成的世界(黑色开启,白色关闭)。缩小时,它基本上看起来像白噪声。然而,代替每个块为1个像素,它们是40个像素并且被绘制为图像纹理。 我的游戏以相机为基础,所以你一次只能看到地图的一小部分,你必须移动角色来探索其余部分。

目前,我的游戏只是渲染画布范围内的每个图像(块纹理)。这导致每帧绘制80-100个图像。虽然它在台式计算机上运行良好,但在移动设备上却表现不佳。

考虑到整个游戏中的地图外观并没有改变,我想尝试不同的方法。我创建了一个世界大小的画布,最终大小为1600x24000像素。我将所有纹理绘制到外部隐藏的画布上。这是在初始化时完成的。然后我会使用drawImage中的剪切属性来获取我需要的子部分。当它工作时,它非常迟钝,并使事情比以前更糟糕。此外,图像质量下降到更模糊的外观,这是不可取的。

现在我正在寻找更好地解决这个问题的方法。所以我的问题是,我应该怎么做呢?谢谢。

3 个答案:

答案 0 :(得分:1)

另外两个想法可以提高你的表现:

  • 检查您的整个世界是否已呈现,或仅检查可见图像(在舞台上)。例如,如果它影响性能,请查看世界大小的两倍。如果您只渲染相关图像,则不应该这样做。

  • 使用CocoonJS编译您的应用程序。它承诺将移动设备的应用速度提高10倍。但请注意,它会对您画布周围的html产生严重限制。


过时的回答,认为问题是由于缩小太远造成的:

在3D图形中Mipmaps可用于避免此问题。当物体距离相机较远时,使用基本上较小的图像(即较少的像素)。

如果您使用像 html5 canvas 2D Mipmaps 这样的内容,也许您可​​以找到合适的内容。或者你可以自己构建一个简单的mipmapping算法。

但在投入这项工作之前,请尝试使用1x1像素图像,通过简单地更改所有块图像来实现这种方法的高效性。也许您的性能问题不是由慢速渲染引起的,正如您所假设的那样。如果它没有解决问题,请学习使用分析器。

答案 1 :(得分:1)

当您使用巨大的画布时,您无法确定渲染器是否会加载整个纹理以渲染其中的一部分。既然你看到了巨大的性能下降,那很可能会发生。

我会做的一些事情:
•只尝试使用fillRect来查看drawImage的责任 •尝试一次性设置上下文然后只使用最简单的drawImage:

var topLeft = { col:12, row : 6 }; // shift of the left-most rect (indexes)
context.save();
context.scale( scale, scale); 
for  column = 0 to columnSeenCount 
     for row = 0 to rowSeenCount
         image = the image of  ( topLeft.col + column , topLeft.row + row )
         context.drawImage( image, column, row) ;
context.restore(); 

这样你就可以避免为每个drawImage重新计算一个变换矩阵。渲染器的数学运算要少得多。

•如果你自己做drawImage,尝试只使用圆角坐标,它会更快 •您还必须对比例进行舍入以防止出现伪影。您可以在1上舍入,但是对于比例,它可能是一个极限:您可以轻松地“舍入”到0.5或0.25或......通过执行:

  var precision     = 2 ;     //  0 => floor ; 1 => at 0.5 ; 2 => 0.25 ; .... 
  var factor        = 1 << precision ;
  var roundedFigure = Math.floor( figure * factor) / factor ;

•如果你的应用程序完成的方式可以很容易地为每个tile类型绘制tile类型,那么你可能会赢得一些时间(你将从缓存中的图像中获益)。

•之后,您唯一的选择就是使用webGL或基于webGL的渲染器......

答案 2 :(得分:0)

有几个问题和想法:

我同意@ GameAlchemist的提示,使用drawImage的剪辑版本要慢于将“单独的图块”图像“blitting”到画布上。当你有这么大的地图图像时,请使用单独的图像。

24000像素的宽度太大,无法包含在任何1张图片中。

看起来你正在横向平移。您可以将24000像素宽的图像切割成更合理尺寸的单个图像。每个图像可能是屏幕宽度的3倍。当用户平移超出当前图像的边缘时,交换图像。

您使用了多少个唯一块图像切片?

当您检测到移动用户时,可能会减少唯一切片的数量。然后将每个独特的图块放在单独的图像或画布上。

你的地图主要是1种瓷砖类型(例如白/关)?

如果是这样,您可以制作1张足够白色网格的单个图像来填充整个画布。然后在必要时添加黑色瓷砖。这会将您的绘图减少为1个白色网格图像以及任何所需的黑色图像。