是英雄就下100层是一款经典的手机小游戏,以前是在诺基亚手机上十分有名。今天我们就用HTML5和lufylegend一步步地实现它。

一,准备工作

首先,你需要下载lufylegend,下载地址如下:

http://lufylegend.googlecode.com/files/lufylegend-1.7.0.rar

接着你需要了解lufylegend,API介绍如下:

http://lufylegend.com/lufylegend/api

接下来我们准备几张图片:

人物图片

游戏背景

游戏旁边的墙

顶部的钉子

有朋友也许看了就喷血了,内心坚强的估计都想打我了。因为我的人物图片是三国志曹操传里的。其实在下也是没办法呀,找不到图了,只有用这一张稍微长得帅一点的士兵哥哥了。

接着让我们来做初始化,首先我们需要几个层用来放人物,背景,建筑物,障碍等,所以首先定义了几个层变量。

  1. var backLayer,loadingLayer,mapLayer,stageLayer,buildingLayer,charaLayer,overLayer;

另外一些杂七杂八的变量,都添了注释,应该能看懂的:

  1. //加载图片用的数组
  2. var imglist = {};
  3. var imgData = [
  4. {name:"player",path:"./images/player.png"},
  5. {name:"back",path:"./images/gameback.png"},
  6. {name:"apron",path:"./images/apron.png"},
  7. {name:"nail",path:"./images/nail.png"}
  8. ];
  9. //人物变量
  10. var hero;
  11. var charaIniX = 100;
  12. var charaIniY = 100;
  13. var isMirror = false;

然后进行游戏初始化:

  1. init(30,"mylegend",stageWidth,stageHeight,main);

init是lufylegend中初始化函数,用法可以到api里面查,这里不多啰嗦了,接下来看看main函数里的东西:

  1. function main(){
  2. //初始化加载层
  3. loadingLayer = new LoadingSample1();
  4. addChild(loadingLayer);
  5. //载入图片,并显示进度条
  6. LLoadManage.load(
  7. imgData,
  8. function(progress){
  9. loadingLayer.setProgress(progress);
  10. },
  11. function(result){
  12. imglist = result;
  13. removeChild(loadingLayer);
  14. loadingLayer = null;
  15. //开始游戏初始化
  16. gameInit();
  17. }
  18. );
  19. }

这个main函数是在做游戏中的图片加载,加载完后调用gameInit。可以在上面定义的变量中找到imgData,不难看出它是装有图片路径的数组,加载时就加载就能将游戏中的图片一张张地加入到了游戏中。至于LLoadManage的方法可以在api里看看,因为即使我来解释,我也只能抄抄api里的东西。

接下来看看gameInit:

  1. function gameInit(){
  2. //初始化层
  3. initLayer();
  4. //加入游戏人物
  5. addChara();
  6. //加入游戏事件
  7. addEvent();
  8. //加入游戏背景
  9. addGameBack();
  10. //加入游戏挡板
  11. addApron();
  12. //加入顶部钉子
  13. addNail();
  14. }

上面的代码都加了注释,应该不难看懂。(其实也应该看懂,因为全是调用函数)

到此,游戏初始化搞定。

二,游戏背景的实现

刚才我们看了gameInit,里面的动西我们还讲完,我们挨着挨着看里面调用的函数。

首先是initLayer,看英语就能知道是初始层,具体代码如下:

  1. function initLayer(){
  2. //加入底层
  3. backLayer = new LSprite();
  4. addChild(backLayer);
  5. //加入地图层
  6. mapLayer = new LSprite();
  7. backLayer.addChild(mapLayer);
  8. //加入障碍层
  9. stageLayer = new LSprite();
  10. backLayer.addChild(stageLayer);
  11. //加入建筑层
  12. buildingLayer = new LSprite();
  13. backLayer.addChild(buildingLayer);
  14. //加入人物层
  15. charaLayer = new LSprite();
  16. backLayer.addChild(charaLayer);
  17. //加入其他层
  18. overLayer = new LSprite();
  19. backLayer.addChild(overLayer);
  20. }

首先我将刚刚定义的层变量通通实例化为LSprite,可能懂点ActionScript的朋友们知道这个东西(虽然我不懂ActionScript),它就相当于一个容器,里面可以放图片,文字,按钮,绘制的图……凡所能放的,无所不能放,这就是LSprite。LSprite可以理解成一个层,因为用它可以轻易地实现层次化效果。

由于引擎是仿照Actionscript语法开发的,所以用法和ActionScript中的一样。当然不懂这玩儿意的朋友可以再去翻翻api,里面的介绍很详细。

添加好层了之后,我们开始加入人物。

看看addChara里的代码:

  1. function addChara(){
  2. //创建一个人物
  3. hero = new Charactor();
  4. //确定人物位置
  5. hero.x = charaIniX;
  6. hero.y = charaIniY;
  7. //加入到人物层
  8. charaLayer.addChild(hero);
  9. }

这里的代码一会儿单独讲,这里不作细讲。

接着是加入事件,大家可以看看代码:

  1. function addEvent(){
  2. //加入鼠标事件
  3. backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,onDown);
  4. backLayer.addEventListener(LMouseEvent.MOUSE_UP,onUp);
  5. //加入onframe调用
  6. backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);
  7. }
  8. function onDown(event){
  9. //取出鼠标坐标
  10. var mouseX = event.offsetX;
  11. //判断人物移动方向【点击人物右边,让人物向右移动;点击人物左边,让人物向左移动】
  12. if(mouseX > hero.x+20){
  13. //角色向右移动
  14. charaMove("right");
  15. }else if(mouseX < hero.x+20){
  16. //角色向左移动
  17. charaMove("left");
  18. }else{
  19. hero.mode = "stand";
  20. }
  21. }
  22. function onUp(){
  23. //松开鼠标后改变造型
  24. hero.mode = "stand";
  25. //改变站立时的方向和样子
  26. hero.anime.setAction(0,0,1,isMirror);
  27. }
  28. function onframe(){
  29. //使用Charactor中run函数,让人物动起来
  30. hero.run();
  31. }

至于addEventListener的使用方法可以看看api,它和js原来的addEventListener的用法不一样。另外提一下,LMouseEvent.MOUSE_DOWN是鼠标点击事件,LMouseEvent.MOUSE_UP是鼠标弹起事件。LEvent.ENTER_FRAME是时间轴事件,由于我们的界面在不断的刷新,那么每刷新一次我们就调用这个事件所对应的函数。

接下来3个函数全是绘画背景,addNail是加入顶部的钉子,addApron是加入游戏两边的墙,addGameBack是贴背景图。代码如下:

  1. function addGameBack(){
  2. //循环显示背景块,以便用来平铺背景
  3. for(var i=0;i<4;i++){
  4. for(var j=0;j<4;j++){
  5. var backBitmapdata = new LBitmapData(imglist["back"],0,0,130,130);
  6. var backBitmap = new LBitmap(backBitmapdata);
  7. //每画一块后移背景块
  8. backBitmap.x = j*130;
  9. backBitmap.y = i*130;
  10. mapLayer.addChild(backBitmap);
  11. }
  12. }
  13. }
  14. function addApron(){
  15. //循环显示挡板块,以便用来铺出两条挡板
  16. for(var i=0;i<15;i++){
  17. for(var j=0;j<2;j++){
  18. var apronBitmapdata = new LBitmapData(imglist["apron"],0,0,17,34);
  19. var apronBitmap = new LBitmap(apronBitmapdata);
  20. //每画一块后移挡板块
  21. apronBitmap.x = j*383;
  22. apronBitmap.y = i*34 + 20;
  23. buildingLayer.addChild(apronBitmap);
  24. }
  25. }
  26. }
  27. function addNail(){
  28. //循环显示钉子,以便用来铺出钉条
  29. for(var i=0;i<30;i++){
  30. var nailBitmapdata = new LBitmapData(imglist["nail"],0,0,14,14);
  31. var nailBitmap = new LBitmap(nailBitmapdata);
  32. //每画一块后移钉子
  33. nailBitmap.x = i*14 + 5;
  34. nailBitmap.y = 0;
  35. buildingLayer.addChild(nailBitmap);
  36. }
  37. }

addGameBack中可以看见LBitmap和LBitmapData两个类,它们分别是用来贴图的,LBitmapData里是装图片数据,LBitmap是将LBitmapData里的数据画出。用法可以看看api。由于我们的背景图很小,所以我们为了添满画布,我不得不采用平铺和拉伸两种方法。在考虑采用平铺还是拉伸时,我认为平铺更能将效果处理好一些,拉伸后图片就不好看了。因此我尝试平铺,没想到lufylegend中没有平铺,没办法只有我自己写了。

我计算出有要铺满画布,我们需要横着画四次,竖着画四次。

看代码:

  1. for(var i=0;i<4;i++){
  2. for(var j=0;j<4;j++){
  3. var backBitmapdata = new LBitmapData(imglist["back"],0,0,130,130);
  4. var backBitmap = new LBitmap(backBitmapdata);
  5. //每画一块后移背景块
  6. backBitmap.x = j*130;
  7. backBitmap.y = i*130;
  8. mapLayer.addChild(backBitmap);
  9. }
  10. }

我弄一个循环套循环的方法,让它每铺一块就移动到下一块的位置再继续铺,这样一来就可以铺出背景了。

添加钉子和围墙的方法与其类似,不一一说了。

运行代码,效果很理想:

三,英雄降临(Hero Fall)

这一小节的名字有点奇怪。当然所谓的奇怪当然是后面的那一串英文Hero Fall。其实这个Hero Fall来自最新上映的电影007天幕杀机,它的英文是Sky fall,所以我也借此多打两三个字符。当然,我可不是来和大家交谈电影的,也不是来交谈如何多打写字符。主要目的是开发游戏。哈!

刚刚废话了一下,现在回到游戏中。

首先我们建立一个人物类Charactor,代码如下:

  1. /**
  2. *Charactor人物类
  3. */
  4. function Charactor(){
  5. base(this,LSprite,[]);
  6. var self = this;
  7. //初始化人物模式为"stand"
  8. self.mode = "stand";
  9. //将图片分解为装满坐标的二维数组
  10. var list = LGlobal.divideCoordinate(192,256,4,4);
  11. var data = new LBitmapData(imglist["player"],0,0,48,64);
  12. //添加动画类
  13. self.anime = new LAnimation(self,data,list);
  14. //调整动画
  15. self.anime.setAction(1,0,1,false);
  16. //调整动画频率的相关变量
  17. self.step = 2;
  18. self.stepindex = 0;
  19. }

首先一来就可能有朋友不懂了,base是神马?告诉你吧,是lufylegend中的继承函数,参数分别是:需要继承的类,基类(被继承的类),传给被继承类的参数,当然,api里也有介绍,想了解更多的朋友可以看看。接着我们将目光跳到self.mode这一行,这个mode在游戏中的作用很大,它包括判断是否碰到障碍物,以及任务的方向,这些都归它管。接下来来我们再看看LGlobal.divideCoordinate这个东西,它是专门用来切坐标的,用它可以把一张图片分解成一个二维数组,这样可以用来方便动画处理,可以看看api了解更多。

构造好了就可以在addChara函数中用变量hero实例化。并加到charaLayer中。

再说说LAnimation类,它是一个播放动画的类,它和LGlobal.divideCoordinate用法可以举例说明:

  1. init(100,"legend",800,450,main);
  2. var imgData = [ {name:"player",path:"player.png"} ];
  3. var imglist;
  4. var backLayer,hero;
  5. function main(){
  6. LLoadManage.load(imgData,null,gameInit);
  7. }
  8. function gameInit(result){
  9. imglist = result;
  10. backLayer = new LSprite();
  11. addChild(backLayer);
  12. var list = LGlobal.divideCoordinate(256,256,4,4);
  13. var data = new LBitmapData(imglist["player"],0,0,64,64);
  14. hero = new LAnimation(backLayer,data,list);
  15. backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);
  16. }
  17. function onframe(){
  18. hero.onframe();
  19. }

LAnimation类官方说明:

LAnimation类 LAnimation(layer,data,list)

■作用:
实现简单动画的播放,原理是将一张大的图片,按照保存有坐标的二维数组保存的坐标来逐个显示。
■参数:
layer:LSprite显示层
data:LBitmapData对象
list:装有坐标的二维数组
 

上面的三个参数中,layer是一个LSprite对象,data是一个LBitmapData对象,这些都比较好理解,第三个参数list是一个二维数组,它的格式如下:

  1. [
  2. [{x:0,y:0},{x:0,y:0},{x:0,y:0}],
  3. [{x:0,y:0},{x:0,y:0},{x:0,y:0}],
  4. [{x:0,y:0},{x:0,y:0},{x:0,y:0}]
  5. ]

LAnimation对象的setAction函数,有四个参数,分别为:

  1. LAnimation.setAction(rowIndex,colIndex,mode,isMirror)
  2. 参数:
  3. rowIndex:播放动画的行号
  4. colIndex:播放动画的列号
  5. mode:(1,0,-1)分别代表(正序播放,静止,倒序播放)
  6. isMirrorBoolean型,当设定为true的时候,图片显示为水平翻转后的镜像

详细的使用方法还可以看看api。

接着添加Charactor中的run,再在run里加入动画,这样的话,人物就可以动起来了。

看看run方法:

  1. Charactor.prototype.run = function (){
  2. var self = this;
  3. //将人物不断下落
  4. self.y += fallSpeed;
  5. //减少动画切换的频率
  6. if(self.stepindex++ > self.step){
  7. self.stepindex = 0;
  8. self.anime.onframe();
  9. }
  10. //判断人物模式,以便用来移动人物
  11. if(self.mode == "left"){ //向左移动时的处理
  12. //判断人物是否到了最左画布边缘
  13. if(self.x > 10){
  14. self.x -= heroSpeed;
  15. }
  16. }else if(self.mode == "right"){ //向右移动时的处理
  17. //判断人物是否到了最右画布边缘
  18. if(self.x < LStage.width - self.getWidth()-20){
  19. self.x += heroSpeed;
  20. }
  21. }else if(self.mode == "stand"){
  22. return;
  23. }
  24. }

再定义控制下降速度和行走速度变量:

  1. var heroSpeed = 10;
  2. var fallSpeed = 10;

结合注释看看,其实也不难理解。首先,我们的英雄要不断下降,所以将他的y坐标不断地加。接下来播放人物动画,播放人物动画的代码还是值得我们看看:

  1. if(self.stepindex++ > self.step){
  2. self.stepindex = 0;
  3. self.anime.onframe();
  4. }

是什么意思呢?由于这个run方法是在界面每刷新一次时调用的,刷新频率由于太高了,而我们的人物动画速度是根据这个频率决定的,所以,频率有多快这个人物动画就动得这么快。因此我们假如想每100ms播放一下人物动画,就必须设定两个变量,一个是刷新次数变量另一个是限定变量。限定变量 = 要求频率÷刷新频率,刷新次数变量初始值 为0。让刷新次数变量在每次刷新后加一,然后判断是否大于那个限定变量,如果是就将刷新次数变量设为0,并播放一帧。这样就可以限定动画频率了。

接下来我们根据mode来判断人物行走方向,以及是否是行走。再看一遍代码;

  1. if(self.mode == "left"){ //向左移动时的处理
  2. //判断人物是否到了最左画布边缘
  3. if(self.x > 10){
  4. self.x -= heroSpeed;
  5. }
  6. }else if(self.mode == "right"){ //向右移动时的处理
  7. //判断人物是否到了最右画布边缘
  8. if(self.x < LStage.width - self.getWidth()-20){
  9. self.x += heroSpeed;
  10. }
  11. }else if(self.mode == "stand"){
  12. return;
  13. }

当mode为left时,人物就往左移,减x坐标就可以;当mode为right时,人物就往右移,加x坐标就可以;当mode为right时,人物就不动。

不过mode在哪里去改呢?这还要追溯到addEvent中调用的函数。

再看一下addEvent中调用的函数:

  1. function onDown(event){
  2. //取出鼠标坐标
  3. var mouseX = event.offsetX;
  4. //判断人物移动方向【点击人物右边,让人物向右移动;点击人物左边,让人物向左移动】
  5. if(mouseX > hero.x+20){
  6. //角色向右移动
  7. charaMove("right");
  8. }else if(mouseX < hero.x+20){
  9. //角色向左移动
  10. charaMove("left");
  11. }else{
  12. hero.mode = "stand";
  13. }
  14. }
  15. function onUp(){
  16. //松开鼠标后改变造型
  17. hero.mode = "stand";
  18. //改变站立时的方向和样子
  19. hero.anime.setAction(0,0,1,isMirror);
  20. }
  21. function onframe(){
  22. //使用Charactor中run函数,让人物动起来
  23. hero.run();
  24. }

当按下鼠标时,我们在addEvent中调用的是onDown函数。接着看看onDown函数:

  1. function onDown(event){
  2. //取出鼠标坐标
  3. var mouseX = event.offsetX;
  4. //判断人物移动方向【点击人物右边,让人物向右移动;点击人物左边,让人物向左移动】
  5. if(mouseX > hero.x+20){
  6. //角色向右移动
  7. charaMove("right");
  8. }else if(mouseX < hero.x+20){
  9. //角色向左移动
  10. charaMove("left");
  11. }else{
  12. hero.mode = "stand";
  13. }
  14. }

首先我们取出鼠标坐标,然后判断这个位置是在人物的哪个方向,也就是判断x坐标哪个大。如果鼠标x坐标大,说明在右边,接着调用charaMove并给参数赋值为right;如果人物x坐标大,说明在左边,接着调用charaMove并给参数赋值为left;如果不大不小就就站在原地。

看看charaMove里的代码:

  1. function charaMove(direction){
  2. switch(direction){
  3. case "right":
  4. //改变人物模式"right",使其转换方向
  5. hero.mode = "right"
  6. hero.anime.setAction(1,0,1,true);
  7. //改变站立时的方向变量
  8. isMirror = true;
  9. break;
  10. case "left":
  11. //改变人物模式为"left",使其转换方向
  12. hero.mode = "left"
  13. hero.anime.setAction(1,0,1,false);
  14. //改变站立时的方向变量
  15. isMirror = false;
  16. break;
  17. }
  18. }

这段代码进入后就判断参数是什么,当为right就将人物的mode设定right,并改变人物样式。当为left就将人物的mode设定left,并改变人物样式。

当松开鼠标时就调用onUp,如下:

  1. function onUp(){
  2. //松开鼠标后改变造型
  3. hero.mode = "stand";
  4. //改变站立时的方向和样子
  5. hero.anime.setAction(0,0,1,isMirror);
  6. }

代码很简单,也就是当松开鼠标后便改变人物的样子和方向。

接下来看看onframe:

  1. function onframe(){
  2. //使用Charactor中run函数,让人物动起来
  3. hero.run();
  4. }

由于onframe是界面每刷新一次就调用一次,所以如果人物的mode改了,就会马上做出反应。

好了,运行一下看看:

按下鼠标:

测试地址:http://www.cnblogs.com/yorhom/archive/2013/04/06/3002850.html

还不错吧,英雄果然是不断下降,并且如果按下鼠标英雄会移动。

现在这个英雄是一个拿给我们玩弄的傀儡,因为这里没有他想看到的跳板。

下一次就来完成跳板和减血这一方面的内容。希望大家多支持。

本次源码下载:http://files.cnblogs.com/yorhom/jump(1).rar

『HTML5挑战经典』是英雄就下100层-开源讲座(一)从天而降的英雄的更多相关文章

  1. 『HTML5挑战经典』是英雄就下100层-开源讲座(二)危险!英雄

    本篇为<『HTML5挑战经典』是英雄就下100层-开源讲座>第二篇,需要用到开源引擎lufylegend,可以到这里下载: 下载地址:http://lufylegend.googlecod ...

  2. HTML5游戏开发_是男人就下100层

    项目流程 市场调研(可行性分析)--> 可行性报告书  需求分析师.客户经理 需求分析--> 需求说明书  项目经理.需求分析师 概要设计--> 概要设计说明书(ER图, UML)  ...

  3. 超多经典 canvas 实例,动态离子背景、移动炫彩小球、贪吃蛇、坦克大战、是男人就下100层、心形文字等等等

    超多经典 canvas 实例 普及:<canvas> 元素用于在网页上绘制图形.这是一个图形容器,您可以控制其每一像素,必须使用脚本来绘制图形. 注意:IE 8 以及更早的版本不支持 &l ...

  4. 『HTML5实现人工智能』小游戏《井字棋》发布,据说IQ上200才能赢【算法&代码讲解+资源打包下载】

    一,什么是TicTacToe(井字棋) 本游戏为在下用lufylegend开发的第二款小游戏.此游戏是大家想必大家小时候都玩过,因为玩它很简单,只需要一张草稿纸和一只笔就能开始游戏,所以广受儿童欢迎. ...

  5. HTML5小游戏【是男人就下一百层】UI美化版

    之前写的小游戏,要么就比较简单,要么就是比较难看,或者人物本身是不会动的. 结合了其它人的经验,研究了一下精灵运动,就写一个简单的小游戏来试一下. 介绍一下几个主要的类: Frame:帧的定义,主要描 ...

  6. Unity经典游戏教程之:是男人就下100层

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  7. 『HTML5梦幻之旅』-缤纷多姿的烟花效果

    天花无数月中开,五采祥云绕绛台.堕地忽惊星彩散,飞空旋作雨声来.怒撞玉斗翻晴雪,勇踏金轮起疾雷.更漏已深人渐散,闹竿挑得彩灯回. ——明·瞿佑·<烟火戏> 记得每年过春节的那段时间,除了欣 ...

  8. 关于『HTML5』:第二弹

    关于『HTML5』:第二弹 建议缩放90%食用 咕咕咕咕咕咕咕!!1 (蒟蒻大鸽子终于更新啦) 自开学以来,经过了「一脸蒙圈的 半期考试」.「二脸蒙圈的 体测」的双重洗礼,我终于有空肝 HTML5 辣 ...

  9. 关于『HTML5』第一弹

    关于『HTML5』:第一弹 建议缩放90%食用 祝各位国庆节快乐!!1 经过了「过时的 HTML」.「正当时的 Markdown」的双重洗礼后,我下定决心,好好学习HTML5  这回不过时了吧(其实和 ...

随机推荐

  1. tp-04 框架与模板的整合

  2. 【转】社区O2O的增量与存量,机会在哪?

    在[O2凹凸社]的前一篇<社区O2O创业百态:三教九流>中总结过目前社区O2O行业的创业氛围,那更进一步看为何有这么多创业者想进入社区O2O市场呢?社区O2O的吸引力在哪?机会又在哪? 一 ...

  3. 数据库 proc编程六

    #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <stri ...

  4. Hadoop、Pig、Hive、NOSQL 学习资源收集

    转自:http://www.cnblogs.com/zzjhn/p/3855566.html (一)hadoop 相关安装部署 1.hadoop在windows cygwin下的部署: http:// ...

  5. 【NOIP模拟题】行动!行动!(spfa+优化)

    spfa不加优化果断tle最后一个点................... 这题和ch的一题很像,只不过这题简单点,这是一个层次图,即有很多个相同的图,这些相同的图之间又存在着练习.. 然后每一次队列 ...

  6. ES 中的 POST 和 PUT 的区别

    0.什么是Restful架构 比较难说清楚,这部分大雾状态,引ruanyf 理解RESTful架构 的几句总结吧: Fielding将他对互联网软件的架构原则,定名为REST,即Representat ...

  7. MathType中空格个数怎么显示

    在使用Word文档的时候很时候用原软件自带的公式编辑器不是很好用,也不方法.MathType就是来解决这个问题的,但是一些用户在使用过程中发现不会看究竟输了多少空格,只能估摸大概.下面本MathTyp ...

  8. 【代码备份】NLM插值

    文件路径: main.m: %% 测试函数 clc,clear all,close all; %输入的原始小图 ima_ori=double(imread('F:\Users\****n\Docume ...

  9. (转)python中的参数:*args和**kwargs

    def foo(*args, **kwargs):print 'args = ', argsprint 'kwargs = ', kwargsprint '---------------------- ...

  10. Sublime Text2.0.2注冊码

    // Sublime Text 3 License Keys // Sublime Text 2.x -– BEGIN LICENSE -– Andrew Weber Single User Lice ...