参考: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。
经过不断地改进,现在它仅使用了canvas和Javascript(最初的代码是基于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.width、canvas.style.height)和canvas有效区域的尺寸(canvas.width、canvas.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等等),你的代码就不会被调用。
这能改善性能,因为浏览器可以优化并发渲染从而提高动画的流畅性(如你的渲染周期太长的话浏览器会将它与其本身的渲染及动画周期同步)。
代码很清晰(别忘了window前缀):
var intervalID = -1;
var QueueNewFrame = function () {
if (window.requestAnimationFrame)
window.requestAnimationFrame(renderingLoop);
else if (window.msRequestAnimationFrame)
window.msRequestAnimationFrame(renderingLoop);
else if (window.webkitRequestAnimationFrame)
window.webkitRequestAnimationFrame(renderingLoop);
else if (window.mozRequestAnimationFrame)
window.mozRequestAnimationFrame(renderingLoop);
else if (window.oRequestAnimationFrame)
window.oRequestAnimationFrame(renderingLoop);
else {
QueueNewFrame = function () {
};
intervalID = window.setInterval(renderingLoop, 16.7);
}
};
你只需要在rendering loop的结尾调用这个函数并在接下来的代码段里进行注册即可:
var renderingLoop = function () {
…
QueueNewFrame();
};
访问DOM(Document Object Model)
为了优化rendering loop,你必须遵循这条黄金准则:DO NOT ACCESS THE
DOM(不要访问DOM)。即使现代浏览器在这方面做了优化,读取DOM对象属性还是太慢了。
例如,在我的代码里,我使用了Internet Explorer 10
profiler(IE10的提供的分析器,按F12快捷键打开),显示的结果如下:
如图所示,访问canvas的宽度和高度会花费大量的时间!
原始代码如下:
var renderingLoop = function () {
for (var y = -canvas.height / 2; y < canvas.height / 2; y++) {
for (var x = -canvas.width / 2; x < canvas.width / 2; x++) {
…
}
}
};
你可以通过两个变量来预先获取canvas.width 和 canvas.height,然后在后面用变量来代替这些属性值:
var renderingLoop = function () {
var index = 0;
for (var y = -canvasHeight / 2; y <
canvasHeight / 2; y++) {
for (var x = -canvasWidth / 2; x <
canvasWidth / 2; x++) {
…
}
}
};
是不是非常简单?虽然有时候很难注意到这些细节,但是请相信我这绝对是件值得的事。
预先计算
通过分析器得知,Math.atan2函数比较慢。事实上,该操作并不需要在运行时计算,你可以在JavaScript里面加一些代码预先计算出结果。
一般来说,预先计算一些较为费时的代码是一种好方法。这里,在运行rendering
loop之前,我已经计算好了Math.atan2:
// precompute arctangent
var atans = [];
var index = 0;
for (var y = -canvasHeight / 2; y < canvasHeight / 2; y++) {
for (var x = -canvasWidth / 2; x < canvasWidth / 2; x++) {
atans[index++] = Math.atan2(y, x) / Math.PI;
}
}
atans数组的使用明显的提高了性能。
避免使用Math.round, Math.floor 以及
parseInt
最后一点是parseInt的使用:
当你使用canvas时,你需要使用一些整数坐标。实际上,所有的计算都采用的浮点数,你需要将它们转换成整形。
JavaScript 提供了 Math.round, Math.floor 甚至 parseInt
来转换数值。但是这个方法做了一些额外的工作(比如检测数据是不是有效的数值,parseInt
甚至先将参数转换成了字符串!)。在我的rendering loop里面,我需要一个更快的转换方法。
在我的旧的汇编代码里面,我使用了一个小技巧:将数据右移0位。这会将浮点数从浮点寄存器移到整数寄存器,并且是通过硬件转换的。右移0位不会改变数据的值,但是会以整数形式返回。
原始代码如下:
u = parseInt((u < 0) ? texture.width + (u %
texture.width) : (u >= texture.width) ? u % texture.width : u);
以下是改进后的代码:
u = ((u < 0) ? texture.width + (u % texture.width) : (u >=
texture.width) ? u % texture.width : u) >> 0;
当然该方法要求你的数据是合法的数值。
最终结果
实现了上述优化之后得到的结果如下:
你可以看到做了这些基本的功能优化之后的表现。
原始的隧道渲染(没做任何优化):
做完上述优化之后:
下表展示了每项优化对帧速率的影响(在我的机器上):
更进一步
记住这些关键技巧,你就可以为现代浏览器或Windows8制作实时、快速、流畅的游戏了。
分享到:
相关推荐
这个“html5 canvas 游戏”是一个基于HTML5 Canvas技术开发的小游戏,主题是“兔子吃萝卜”,展示了Canvas在游戏开发中的应用。 HTML5是下一代超文本标记语言,其Canvas元素是其中的重要组成部分。Canvas提供了一个...
HTML5 Canvas是Web开发中的一个强大工具,它允许开发者在网页上进行动态图形绘制,为创建交互式游戏、动画和应用程序提供了可能。本书《HTML5 Canvas游戏开发实战》由张路斌(lufy_legend)编写,深入浅出地讲解了...
标签“HTML 5 CANVAS 游戏 实战”强调了书籍的主要内容,即在实战中使用HTML 5的CANVAS元素来开发游戏。标签的使用帮助读者快速了解书籍的核心议题,同时方便了分类检索。 至于提供的部分参考内容,出现了大量的...
HTML5 Canvas核心技术源码技术代码、图形、动画与游戏开发。 Canvas开发、入门学习Canvas技术代码。 HTML5 Canvas核心技术源码技术代码、图形、动画与游戏开发。 Canvas开发、入门学习Canvas技术代码。 HTML5 Canvas...
在HTML5 Canvas上开发游戏通常涉及到以下几个关键知识点: 1. **Canvas API**: HTML5 Canvas提供了一系列方法,如`fillRect()`、`strokeRect()`、`arc()`、`beginPath()`、`moveTo()`和`lineTo()`等,用于绘制线条...
基瑞编著的《HTML5Canvas核心技术:图形动画与游戏开发》是HTML5 Canvas领域的标杆之作,也是迄今为止该领域内容最为全面和深入的著作之一,是公认的权威经典、Amazon五星级超级畅销书、资深技术专家David Geary*...
在这个“html5 canvas填色画游戏代码”中,我们主要关注以下几个知识点: 1. **HTML5 Canvas**: HTML5 Canvas是一个基于矢量图形的元素,通过JavaScript API可以进行动态绘图。开发者可以通过调用其提供的方法,如`...
在HTML中,我们首先需要定义一个`<canvas>`标签,为游戏提供一个画布区域。例如: ```html <canvas id="gameCanvas" width="800" height="600"></canvas> ``` 这里设置了画布的宽度和高度,以便适应游戏的需求...
在游戏逻辑中,这可以用来切换不同状态的绘图,比如正常状态和选中状态。 6. **动画制作**:通过定时器(如`requestAnimationFrame()`)可以实现连续的动画效果,例如连连看游戏中的棋子翻转或消除效果。 7. **...
HTML5 Canvas是Web开发中的一个关键技术,它提供了一个在网页上绘制图形的API,使得开发者可以直接在浏览器中创建丰富的交互式2D图形、动画以及游戏。"HTML5 Canvas核心技术—图形、动画与游戏开发"这本书深入浅出地...
HTML5 Canvas核心技术 图形、动画与游戏开发
高清版 HTML5 CANVAS核心技术图形动画与游戏开发(爱飞翔).pdf
5. **音频集成**:HTML5的`Audio` API和如何在游戏中的适时播放音乐和音效。 配合书中的源码,读者可以更直观地理解这些概念,并动手实践,解决实际问题,例如动画的实现和游戏逻辑的设计。通过这本书,无论是初学...
在游戏开发中,碰撞检测是关键。可以使用几何形状的相交检测,如矩形与矩形、圆形与圆形的碰撞,或者更复杂的像素级碰撞检测。 五、事件处理 HTML5 Canvas本身没有内置的事件处理机制,但可以通过监听画布元素的...
《HTML 5 Canvas基础教程》从HTML5和JavaScript(以及jQuery)的基础知识讲起,全面介绍了HTML5Canvas的各种特性,包括渲染上下文、坐标系统、绘制图形、保存和恢复画布状态,以及变形、合成、处理图像和视频等,让...
html5 canvas飘洒的星星特效html5 canvas飘洒的星星特效html5 canvas飘洒的星星特效html5 canvas飘洒的星星特效html5 canvas飘洒的星星特效html5 canvas飘洒的星星特效html5 canvas飘洒的星星特效html5 canvas飘洒的...
在这个"html5 canvas实现的手机端斗地主游戏源码.zip"压缩包中,我们可以深入理解如何利用HTML5 Canvas技术来开发一款移动端的斗地主游戏。 首先,Canvas API提供了基本的绘图命令,如画线、填充矩形、绘制圆形、...
"h5 canvas赛车游戏"就是利用HTML5的Canvas元素构建的一款赛车游戏,它展示了Canvas在游戏开发中的强大潜力。 在Canvas上创建赛车游戏,首先要理解其基本绘图操作,包括画线、画圆、填充颜色、描边样式等。开发者会...
在这个“是男人就撑过20秒”躲避游戏中,HTML5 Canvas被用来创建一个动态的游戏环境,玩家需要操控角色避开不断出现的障碍物,目标是在20秒内尽可能生存。 首先,Canvas API提供了基本的绘图方法,如`fillRect()`...