,前提是这款游戏存在对应的Android版本。下载之后将apk扩展名修改为rar并解压,这样你就可以从解压后的目录中找到所有的图片和音频资源。注意:有些游戏对资源进行了压缩和处理,这样你就很难获取到了。)

在游戏源码的根目录,当你打开index.html就可以快速预览游戏的效果了(当然,这需要你的浏览器支持HTML5部分特性)。

游戏的核心框架是myEngine目录,这也是本节介绍的重要。myEngine目录中包含了与游戏业务逻辑无关的核心库,它与你所接触过的jQuery、Ext等框架一样,封装了一系列常用的处理逻辑;在它的基础上,你可以更简单地编写少量的代码,来完成你的游戏。

按照游戏index.html文件中引入的脚本顺序,我将依次说明游戏框架中每个文件的含义:

首先是core目录下的my.js,这是框架的核心文件,它包含了一些常用的公共函数,如果你已经了解了JavaScript面向对象相关的知识,那么很容易可以看懂文件中所有的代码。

component/Component.js:Component是所有游戏组件的基类,所有的游戏组件均继承自它,Component类提供了组件对象的创建、初始化、销毁等公共方法。

component/DisplayObject.js:DisplayObject是所有可显示组件的基类,游戏中所有能显示的组件,都应该继承它,因为它提供了一套统一的处理对象显示的方法:显示隐藏控制、透明度、旋转、翻转、缩放、渲染控制等。

component/DisplayObjectContainer.js:DisplayObjectContainer是一个组件容器类,它本身也是一个DisplayObject对象,但它可以容纳其它更多的DisplayObject和DisplayObjectContainer对象,便于统一管理。例如:一个房间内的场景包含了桌子、椅子、衣柜、书架等DisplayObject(或DisplayObjectContainer)对象,而这个房间就是一个DisplayObjectContainer对象,房间被销毁,房间内的所有东西也不会再存在;这样你就不需要再把房间内的东西一个个地销毁掉。

component/Bitmap.js:图像对象,如果你要在游戏中显示一副图像,可以创建一个Bitmap对象。

component/Animation.js:帧动画控制类,由多幅图像组成,在固定的频率中不断切换,形成动画的效果。使用它,可以方便地创建一个帧动画,并控制它的显示、隐藏和播放等行为。

component/Sprite.js:游戏中所有精灵的基类,如果对“精灵”的概念还不是很清楚,建议按照第一节中介绍的学习过程再巩固一下。它提供了一个精灵的基础方法和属性,包括移动、动画控制和碰撞检测。

component/Viewport.js:视口对象,游戏地图可能会很大,但能够同时看得到的区域可能只是一个固定的尺寸,当游戏角色或场景移动时,地图也会移动,玩家会感觉是通过一个视口在观察角色和地图的移动。这里的视口对象,就是用来处理视口的移动,以及保存视口状态的。

component/Layer.js:游戏的分层,一个游戏中可能包含许多内容,比如主角、玩家、NPC、怪兽、道具、效果、地图和其它场景,我们没必要把它们堆到一起,这样你无法进行管理和维护,因此我将它们放到多个层级,就可以方便地对每个层级内的元素进行统一控制。

这里的分层不仅仅是在逻辑上将不同类型的元素分离开,不同的Layer对象还可以配置到不同的Canvas画布上,这是提升性能的一种重要的方式,后面会详细讨论。

component/Game.js:游戏基类,用于控制游戏的帧频、画布的刷新、开始和结束游戏,以及游戏时间相关的记录。

event/KeyEvent.js:监听用户按键事件,如果你查看过这个文件的源码,相信我不用作太多介绍你就会明白。它不会绑定具体的事件在用户的某个按键上,它只提供一些控制和查询当前按键状态的方法。

utils/ImageManager.js:图像管理类,使用Canvas绘图前,首先需要保证图片已经被完全加载完毕,而游戏中使用的图片非常多,因此如何统一控制加载和管理,就由ImageManager来发挥了。

utils/DOM.js:提供了一套类似于jQuery的DOM操作方法,之所以不使用jQuery,是因为对这个游戏来说,jQuery显得有些大材小用,没有必要为了使用其中的几个方法,加载整个库。

utils/Math.js:提供一些基础的算数运算方法。

utils/buzz.js:这是一个第三方音频管理库,作用和ImageManager类似,不过是用于控制音频文件的加载和播放。其实框架中是包含了一个我自己写的音频管理类,这里之所以使用第三方库,是因为我还不能完全确保那个音频管理类的稳定性。

另外,框架中还包含了一些游戏中没有使用到的文件,比如:ScriptManager(脚本动态加载和管理)和Astar(自动寻路算法),这里我就不作介绍了。

以上是游戏框架中的全部内容,具体细节建议阅读源码,源码中标注有详细的注释。

如果你接触过Ext框架或Flex,你会很容易理解这里大部分类的作用和功能,因为它们有许多相似之处。

这套框架我一共重写了4次,每一次都会有许多提升。这里所说的提升并非是指功能的增强,相反,这个版本和第1次完成时相比,功能已经被删减掉了一大部分,之所以这样做,仅仅是为了做到需求、工作量和性能之间的平衡(性能相关的问题,我们放到后面再讨论),我认为在能实现需求的前提下,最重要的就是尽可能的简单、快速。

我在这里回顾一下之前删减掉的一些功能:

类似DOM Level 2中的事件模型,包含Event、EventDispatcher、EventManager和Component下具体子类的事件模型类。之所以删掉它们,是因为我完全可以使用类似DOM Level 1中的事件模型来代替它们,而这样做会更简单,更高效。当然也会牺牲一些扩展性和耦合度,但我认为这是值得的。

以前的Animation类,是一个继承自DisplayObjectContainer的子类,它包含了一系列Frame(单帧)对象,而Frame对象中又包含了Bitmap(图像)对象和CollRect(碰撞区域)对象;当初之所以有这么多东西,是因为考虑到动画对图像文件和绘制图形之间的转换,以及支持多种碰撞检测方式。这种做法后来也被我否决了,原因与和前面一点一样,出于简单开发和高效性能的考虑。

而现在优化后的Animation类十分简单,它本身只是一个Component组件,通过简单配置图像URL和帧数据,就可以实现一个帧动画。当然,这种做法就受到许多约束,例如:一个动画中所有的帧图像必须是同一个Image对象,还有Animation本身不提供渲染的方法,它必须依附在一个Sprite(精灵)对象中。

删除了Level和Scene类,Level类是用来做游戏关卡控制和调度关卡数据的,而Scene类用作场景的切换、初始化、缓存场景数据以及处理Layer(分层)的视差效果。

现在我把分层的视差效果直接放到了Layer本身,通过定义Layer对象的distance属性(即定义分层与视口之间的距离),就会自动形成视差效果。

例如:在这个游戏中,驴子刚开始跳跃时,驴子身后的房子、山丘、高山、和天空在视觉上的移动速度是不一样的,物体距离相对驴子越远,视觉上移动距离越小;这些背景实际上是存储在多个Layer中,而我只需要通过定义每个Layer的distance属性,就可以实现这个效果。

如果你想开发一套成熟的游戏框架,这些功能或许是非常必要的。因此,我并不能保证删减这些功能是正确的做法,但对于具体需求来说,我认为这样做会更合适。

(如果你也需要这些代码,可以联系我。)

-----------------------------------------------------------------------------------

三、开发一个“驴子跳”游戏

到目前为止,我已经介绍了学习方法、和基础框架的搭建;此时你应该花更多的时间去编写和优化你的框架,让它更简单、更稳定以及更加“坚固”。如果你还有不明白的地方,可能是我描述的不够清楚和准确,也可能是你所花的时间还不够多;无论如何,你都可以联系我一起研究学习。

如果你对前面讲解的内容没有太多的困惑,本节将着重讨论如何在框架库的基础上,开始开发游戏。这个过程会让你非常心动,因为不久你就可以看到游戏的样子了。

我第一步要做的就是将整理游戏资源,提取游戏中图片和音频文件的方法可以参考第二点中的内容。

首先是整理图片资源,我使用Photoshop对图片尺寸进行调整,更重要的是将图片进行合并;这将减少资源的请求数,提高加载效率;另外,这也是我框架库中Animation类所强制要求的(前面提到过,Animation要求动画中所有的帧图像为同一个Image对象)

其次是整理音频文件,目前各浏览器还没有统一支持的音频格式,因此我们必须使用两套同样的音频文件,关于目前各浏览器所支持的音频格式如下:

浏览器   支持的音频格式

IE9 mp3, aac wav

Firefox ogg, wav

Chrome ogg, mp3, aac, wav

Safari mp3, aac, wav

Opera ogg, wav

游戏中的音频文件是mp3格式,为了兼容Firefox和Opera,我同时还选择了wav格式。wav格式的文件非常大,为了减小文件大小,我将音频进行了压缩,减小比特率,但音质受到了明显的影响。可能你会疑惑,为什么我不选择ogg格式呢?这是因为我购买的虚拟主机竟然不支持访问ogg格式的文件,Why?

这里,我建议你可以仍然使用ogg格式,在保持和mp3同样音质的情况下,文件大小会比wav小很多。

资源的整理可能需要花上好几天的时间,不过幸运的是,这些资源我已经整理过一遍,你可以copy过去直接使用。

资源整理完毕后,我创建一个了项目,分好目录结构,并将资源放在对应的目录下。然后创建游戏页面index.html。

经过分析,我将尽量能使用HTML和CSS来做的内容独立开来,使用HTML和CSS进行开发(index.html文件中包含了所有的HTML,css目录下包含了所有的样式);还缺少什么呢?对了,还缺少对DOM的控制逻辑,这么多的HTML,在游戏进行到什么时候显示?什么时候隐藏?如何控制?这些具体的逻辑我们都用不管,先编写一个统一的UI控制类,代码存放在js/classes/UI.js,UI类不包含任何游戏逻辑,它只负责处理DOM相关的UI展现和控制,在游戏中需要使用到它的时候,调用相应的方法即可。

另外在UI类中,也包含了类似于DOM Level 1的事件管理方式,这是为了降低DOM对象与游戏逻辑间的耦合度。

当这部分内容完成的时候,游戏就有了一个可以看到的雏形,但我们还没有真正开始呢,因为我们编写的游戏框架库还没有派上用场。

我先在js目录下创建一个main.js,用作游戏主逻辑的入口文件(在上一节中,我们介绍过,js目录只用于存放游戏相关的业务逻辑)。

在main.js中,我先加载了游戏资源,在资源加载完毕后,创建游戏对象,并开始监听和处理DOM相关的事件;当你点击“开始”按钮后,游戏就正式开始了。

游戏开始后,具体是怎么运行的,这里就不做描述,源码中有详细的注释,但我觉得还是有必要简单描述下js目录下的所有文件的结构,便于大家查找。

js/main.js:这个文件刚才介绍过,是游戏的主逻辑入口文件。

js/classes:游戏中所有的逻辑代码都存放在这里。

js/classes/Audio.js:Audio类提供一些基础方法,用于控制游戏中音效的播放。

js/classes/Cloud.js:当驴子踩到云朵上时,会产生践踏效果,Cloud就是践踏效果类,用于产生践踏效果对象。

js/classes/Donkey.js:驴子类,用于创建驴子实例,提供控制驴子状态相关的方法。Donkey类继承自Sprite(精灵)类。

js/classes/DonkeyJump.js:DonkeyJump(驴子跳),该类继承自Game类,是整个游戏的核心类,主导游戏整体逻辑和状态,用于创建游戏中的分层,负责游戏初始化、开始、暂停等操作。

js/classes/Prop.js:游戏道具类,游戏中一共有7种道具,但它们都是Prop类的生成对象。

js/classes/Stair.js:云朵类,游戏中的云朵也有7种,包括5种普通云、脆弱的云和会移动的云。云朵的类型是随机的,在云朵被创建时,有一定的几率会同时出现一个道具(道具的类型也是随机选择的)。

js/classes/UI.js:UI类用于控制DOM的展现逻辑,上文中已经进行过讨论。

js/frames:游戏中所有精灵的帧动画配置数据都存放在这里;每个文件存放不同精灵的帧动画数据,此处不一一介绍,只以donke.js为例,当你打开这个文件,会发现里面存储的内容几乎完全一样,它定义了每个动画需要使用的所有帧数据:

Js代码

{ // 这是某一帧的配置数据

x : 0, // 当前帧在动画的Image对象出现的x轴位置

y : 0, // 当前帧在动画的Image对象出现的y轴位置

duration : 10, // 当前帧播放的时间(ms)

collRect : [[50, 93, 28, 15]] // 当前帧的矩形碰撞区域

}

单帧配置中的duration表示该帧在动画过程中所播放的时间,而collRect表示动画被播放到该帧时,精灵对象的碰撞区域。

目前我只支持了矩形碰撞,通过分割定义多个矩形碰撞区域,可以提高碰撞监测的准确度。如果需要更加精确的碰撞检测,就需要使用其它的方式实现,例如像素检测。

js/resources:定义游戏所需要的图片和音频资源路径和配置。

js/resources/audios.js:对游戏中所有的音频资源进行定义

js/resources/images.js:对游戏中所有图片资源进行定义

当你了解了这个游戏的组成,你可以参考游戏的源码,并试着自己也写一遍。当然,我的源码写的不一定好,至少我目前觉得在游戏各对象的耦合关系上处理地还不太好,这也是因为开始写的之前没有全面规划。

到目前为止,你通过阅读以上全文,并付之实践,相信一定可以开发出一个你喜欢的HTML5游戏了。

-----------------------------------------------------------------------------------------------

四、性能优化

在本节,我将分享游戏过程中遇到的种种性能问题,和解决方案,以及一些性能测试数据。在分享这些测试数据之前,我得先说明一下我的机器配置:

ThinkPad SL410K(属于ThinkPad系列中最低端的一款了,伤心ing)

操作系统:Windows 7旗舰版

CPU:Intel奔腾双核T44主频2.2GHz

内存:4GB(标配2GB,自己加了2GB)

硬盘:320G SAT 5400转

显卡:Intel GMA X4500集显 显存256M

(说明:因为只在我一个客户端环境中做测试,因此以下结论可能并非完全正确。)

说到前端的性能优化,不得不提到《高性能JavaScript》一书,书中对网络性能和代码结构优化等方面都有非常全面的解说,在这里我就不班门弄斧了,仅仅说一下在我这个游戏中所涉及到部分内容:

图片合并:这会减少HTTP请求数,提高加载效率,你懂的。

代码合并:这会减少网络传输大小,同样用于提高加载效率,有一些工具可以快速压缩合并你的多个脚本文件,我使用的是JsMinGUI: