You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

10 KiB

第30讲 | 热点剖析试试看你也可以编写一款HTML5小游戏

前两周,我分析了[HTML5的核心竞争力](https://time.geekbang.org/column/article/9298)以及[HTML5游戏的引擎](https://time.geekbang.org/column/article/9702)。选择好了HTML5引擎我们就可以开始制作游戏了。

对于编写HTML5小游戏你或许会很有兴趣因为HTML5现在已然是一个潮流而且利用引擎编写HTML5游戏已经变得相当方便。

如何选择一款引擎?

我选择的是比较容易上手的lufylengend引擎。为什么要选择这款引擎呢因为它只需要下载一个压缩包并且不需要特别繁琐的说明和设置就能直接上手用作我们的教学示例是最合适的。

如果使用白鹭引擎或者Cocos-2d引擎这些比较有名的引擎可能会有这些问题。

  1. 这些引擎从工具到套件都非常成熟,你直接下载一个引擎启动器或者组件管理器,就可以一应俱全地在启动器里面下载,配置到默认路径。但是,这些工具拥有纷繁复杂的界面,你连上手都要费一段时间,更别说短时间内熟练使用并制作出一款游戏。

  2. 这些引擎需要引入的库或者使用的方式极为系统所以你需要系统地引入库文件才可以使用。事实上我要做的示例并不需要很多复杂的东西你只需要跟我从头到尾走一遍就能明白编写HTML5游戏是怎么回事。

  3. 这些引擎需要别的工具支持比如node.js。作为新手来说光配置node.js就是一项比较麻烦的工作。所以我选择了lufylengend引擎这一个比较“单纯的”引擎来作为教学引擎。

几个简单的说明

你可以从这个地址下载最新版本:https://github.com/lufylegend/lufylegend.js/archive/lufylegend-1.10.1.zip 。下载下来的安装包大约有30M大解压缩后有36M左右。解压缩后我们会看到一系列的js文件。

我先对这些文件做一些说明,并且对最基础的编程流程做一个简单的梳理。

压缩包内包含lufylegend-版本号.js和lufylegend-版本号.min.js这两个完整版本还有lufylegend-版本号.simple.js和lufylegend-版本号.simple.min.js这两个缩减版本其中带min字样的是去除了回车和空格的压缩版本。如果你使用JavaScript编程缩减版本对于你来说再熟悉不过的了。

其中simple缩减版本与完整版本的区别在于它将LBox2d、LQuadTree、LTransitionManager、LoadingSample1、LoadingSample2、LoadingSample3、LoadingSample4、LoadingSample5等几个类与HTML5引擎的常用部分分离缩减了引擎的体积。如果需要用到被分离的部分功能的话可以手动进行加载。

随后可以在HTML代码中将legend引擎的库件引入。调用LInit函数初始化库件。然后开始游戏代码的编写。剩下你只需要有一款合适的IDE就可以开始编程了。

对制作HTML5游戏来说你首先要做的是将游戏场景在浏览器中呈现出来。把Windows的窗体从系统客户端程序搬到浏览器上呈现的窗体从可执行文件变成了浏览器。从这个角度讲**浏览器担负了应用层的工作,浏览器本身担负了解释程序,并且渲染的过程,**所以,从理论上讲,相同的游戏类型和游戏内容HTML5游戏的渲染速度是比不上客户端游戏的渲染速度的。

一起动手制作吧!

很凑巧的是lufylengend引擎也拥有一款打飞机demo。我们只需要在lufylegend引擎目录的examples/demo下找到barrage目录。

这一款打飞机的游戏,打开后是这个样子。

这和我们之前讲述的内容非常类似。那我就借解释一下这款游戏的代码,来教你制作。

在目录下有一个index.html这就是游戏的开始页面。在这个页面下我们先来看一下部分代码。

<script type="text/javascript" src="../load_lufylegend.js"></script>
<script type="text/javascript">
if(LGlobal.canTouch){
      LGlobal.stageScale = LStageScaleMode.EXACT_FIT;
      LSystem.screen(LStage.FULL_SCREEN);
}
</script>
<script type="text/javascript" src="./js/Main.js"></script> 

如果你熟悉web编程对于这些代码肯定非常熟悉。在开始的地方我们看到载入的JavaScript代码是load_lufylegend.js这个js文件包含在打飞机游戏的上一层目录内部就只有一行代码。

document.write('<script type="text/javascript" src="../../../lufylegend-1.10.1.min.js"></script> ');

我们看到在这个js文件内包含了lufylegend的原始引擎文件。至于为什么要这么做为什么要使用两个文件包含引擎是因为这样可以保持游戏代码的干净。如果你要修改引擎的包含路径不需要修改游戏本体文件只需要修改load_lufylegend.js包含路径即可。

而LGlobal.canTouch这段话的意思是如果是移动版本的话设置缩放模式为适应屏幕并且为全屏代码是

LSystem.screen(LStage.FULL_SCREEN)

最后导入游戏脚本Main.js文件。

在Main.js里面我们看到它还包含了三个别的js文件代码是这样。

imgData.push({type:"js",path:"./js/Global.js"});
      imgData.push({type:"js",path:"./js/Bullet.js"});
      imgData.push({type:"js",path:"./js/Plain.js"});

它包含了一个共有类Global.js、子弹类Bullet.js以及飞机类Plain.js。之后的代码是这样的。

loadingLayer = new LoadingSample1();
addChild(loadingLayer);

其中LoadingSample1是“载入进度条”类我们可以在下面的代码看到载入的实现。

LLoadManage.load(
imgData,
function(progress){
loadingLayer.setProgress(progress);
},
function(result){
imglist = result;
removeChild(loadingLayer);
loadingLayer = null;
gameInit();
}
);

在载入结束后就开始gameInit函数的调用也就是游戏初始化。

function gameInit(event){
//游戏底层实例化
backLayer = new LSprite();
addChild(backLayer);
ctrlLayer = new LSprite();
addChild(ctrlLayer);

LSprite是引擎的基本显示列表构造里面包含了显示内容的列表节点addChild就是将显示内容添加到节点列表。

//添加游戏背景
bitmapdata = new LBitmapData(imglist["back"]);
bitmap = new LBitmap(bitmapdata);
backLayer.addChild(bitmap);  

这几段代码就是将背景图片也添加到显示节点列表。

//得分显示
pointText = new LTextField();
pointText.color = "#ffffff";
pointText.size = 20;
pointText.text = point;
backLayer.addChild(pointText)

这是一个得分的显示,所以需要新建一个文本类,并设置颜色和大小,并将之放到显示节点的列表。

//加入玩家
player = new Plain("player",0,200,600,[5]);
backLayer.addChild(player);

我们需要新建一个玩家类。新建玩家其实就是新建一个飞机类型所以我们在这里看到一个plain类的创建。

这个创建函数的实现原型是这样的。

function Plain(name,belong,x,y,bullets)

你可能会觉得奇怪Plain是什么意思在它的demo里面Plain是飞机的意思然而可能是作者的一时疏忽或者是英文“捉急”所以就把Plane写成了Plain。以下所有和飞机相关的代码都是Plain虽然并不影响代码的运行但是出于严谨考虑我在这里更正一下Plain等于Plane。

第一个参数是名字第二个参数是飞机所属表明是属于敌人还是玩家随后两个参数x,y是飞机在2D画布上所显示的位置最后一个bullets是子弹的数组。

//添加帧事件,开始游戏循环
backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);
//添加控制事件
backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,ondown);
backLayer.addEventListener(LMouseEvent.MOUSE_UP,onup);
}

在初始化的最后我们需要添加鼠标事件将鼠标事件LMouseEvent的鼠标上下操作事件都放入到事件侦听函数内addEventListener。

看到这里,你不禁会问,按照我们所教学的,游戏应该会有一个大循环来完成游戏的显示、操作等内容。那这个循环在哪里呢?

事实上这个循环,就在上面这串代码中。

backLayer.addEventListener(LEvent.ENTER_FRAME,onframe); 

其中LEvent为事件类。和传统客户端游戏不同在HTML5游戏引擎中循环采用了事件代码来完成只要你在侦听器函数中注册了事件都会一帧一帧不停地调度这个事件以此达到循环的效果。

在这里注册的侦听事件函数就是onframe函数。查看它的源代码你可以看到onframe函数的实现细节我就不在这里进行阐述了。

小结

今天我们使用lufylegend引擎剖析了HTML5游戏的编写方式。我来总结一下。

  • HTML5游戏的启动页是一个HTML文件。这个文件包含引擎的js文件。在其他别的引擎中也是使用类似的方式来加载引擎。包含了引擎就可以针对引擎所封装的接口进行游戏的开发。

  • HTML5游戏的循环方式和传统游戏的循环方式不同。由于HTML5游戏引擎绝大部分是使用JavaScript脚本编写的而JS本身就是以事件驱动的方式来工作的所以使用事件驱动是HTML5游戏引擎的一个很大特点。我们在事件侦听函数中注册一个事件函数,在这个函数内编写“游戏循环”内的代码,就能起到传统游戏循环的作用。

  • 在HTML5游戏中我们几乎不需要关心图片的刷新或者清空操作。这些操作比之传统客户端游戏更为简洁我们只需要关心游戏的图片呈现以及操作即可。

简单来说,**HTML5游戏就是一种使用事件驱动模式并渲染在网页上的一种技术省却了传统游戏的底层操控。**你在制作的时候,可以把更多的关注点放在游戏逻辑和可玩性上。

最后,留一个小问题给你。

在类似这样的HTML5打飞机游戏中碰撞检测是怎么做的呢请结合我以前的讲过的内容给出一个答案。

欢迎留言说出你的看法。我在下一节的挑战中等你!