日期:2014-05-17  浏览次数:20616 次

在游戏中发挥HTML5 Canvas的潜能

参考:http://www.kuqin.com/gamedev/20120505/320360.html

?

?

目前, 支持HTML 5的浏览器和Windows 8 Metro成为了游戏开发的候选方案。

利用canvas(画布)可以实现硬件加速,你可以在上面绘制游戏的内容,通过一些技巧可以达到每分钟60帧的渲染速度。

在游戏中,fluidity(流畅性)这一概念非常重要,因为好的流畅性能带给玩家更好的体验。

这篇文章的主旨在于教你一些技巧,让你可以最大程度地发挥HTML5 canvas的潜能。

我将通过一个例子来表达我要讲的内容。这个例子是2D tunnel effect(2D隧道效应),它是我为Coding4Fun 会议写的(我参加了在法国举办的TechDays 2012)。

(http://video.fr.msn.com/watch/video/techdays-2012-session-technique-coding4fun/zqy7cm8l).

早在80年代,当我还是一个年轻的demomaker的时候曾受到一些Commodore AMIGA代码的启发,从而写了这个2D tunnel effect。

经过不断地改进,现在它仅使用了canvasJavascript(最初的代码是基于68000汇编的):

完整的代码可以从这里获得:http://www.catuhe.com/msdn/canvas/tunnel.zip

这篇文章的目的不是讲解该程序的开发过程,而是让你通过优化已有的代码来达到一个实时性的效果。

使用off-screen canvas(离屏画布)来读取图片数据

我想讲的第一点是怎样使用canvas来读取图片数据。实际上,任何一个游戏都需要图形来显示游戏界面和背景。canvas有一个非常有用的画图方法:drawImage 。这个功能可以用来绘制游戏界面,通过它你可以定义起始和目的区域。

但是有时候光使用它是不够的,比如你想要在源图像上实现一些特效,或者源图像不是一个简单的位图而是一个复杂的资源(如地图)。

在这些情况下,你需要访问到图片的内部数据。但是Image标签无法读到这些数据,这时候就该canvas上场了。

事实上,每当你需要从图片中读取内容的时候,你都可以使用off-screen canvas。也就是说,当你导入一张图片的时候,你只需要将它渲染到canvas中(而不是DOM里),然后你就可以通过读取canvas的像素点来获得源图片的内容了(这个过程非常简单)。

有关部分的代码如下(2D tunnel effect中用来读取隧道的纹理数据的):

var loadTexture = function (name, then) {

var texture = new Image();

var textureData;

var textureWidth;

var textureHeight;

var result = {};

// on load

texture.addEventListener(‘load’, function () {

var textureCanvas = document.createElement(‘canvas’); // off-screen canvas

// Setting the canvas to right size

textureCanvas.width = this.width; //<– “this” is the image

textureCanvas.height = this.height;

result.width = this.width;

result.height = this.height;

var textureContext = textureCanvas.getContext(’2d’);

textureContext.drawImage(this, 0, 0);

result.data = textureContext.getImageData(0, 0, this.width, this.height).data;

then();

}, false);

// Loading

texture.src = name;

return result;

};

为了使用这些代码,你还要保证隧道纹理图片的导入是异步的,因此你需要传递then参数,代码如下:

// Texture

var texture = loadTexture(“soft.png”, function () {

// Launching the render

QueueNewFrame();

});

使用硬件缩放功能

现代浏览器和Windows8都支持硬件加速的canvas,这意味着,你可以使用GPU来调整canvas里面内容的尺寸。

在2D tunnel effect里,该算法要求处理canvas的每一个像素点,因此一个1024×768的canvas就得处理786432个像素点,并且为了达到流畅性的要求,每分钟得处理60次,也就是说每分钟要处理47185920个像素点!

很显然,任何可以减少像素处理总数的方法都能带来极大的性能提升

又一次轮到canvas上场了!下面的代码展示了怎样使用硬件加速来调整canvas的内部有效区域使之等于DOM对象的外部尺寸:

// Setting hardware scaling

canvas.width = 300;

canvas.style.width = window.innerWidth + ‘px’;

canvas.height = 200;

canvas.style.height = window.innerHeight + ‘px’;

请注意DOM对象的尺寸(canvas.style.widthcanvas.style.height)和canvas有效区域的尺寸(canvas.widthcanvas.height)之间的差别。

当这两个尺寸不同的时候,硬件会自动调整有效区域的大小,这是一件很棒的事:我们可以绘制低分辨率的图形,然后通过GPU的调整使之符合DOM对象的大小(实现一个漂亮免费的模糊滤镜效果)。

在这种情况下,本来只有300×200 的图像会被GPU扩展到跟你的窗口一样大。

所有的现代浏览器都支持该功能,因此你可以放心的使用。

优化rendering loop

制作游戏的时候,需要一个rendering loop用来绘制所有的组件(如背景,界面,分数等等)。这个loop是代码的核心,因此必须充分优化从而保证游戏的快速和流畅。

RequestAnimationFrame

HTML5一个有趣的功能是使用window.requestAnimationFrame. 代替window.setInterval 来创建定时器,从而实现每(1000/16) 毫秒渲染一次(以达到60fps),你可以通过requestAnimationFrame将该任务交给浏览器。调用这个方法表明你想要尽快的更新有关的图形。

浏览器会将你的请求放入内部渲染计划,并使之与其本身的渲染及动画代码(CSS, transitions等等)同步。这个方法另一个有趣的地方在于如果窗口不显示(minimized, fully occluded等等),你的代码就不会被调用。

这能改善性能,因为浏览器可以优化并发渲染