Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 1056|回复: 0

『HTML5挑战经典』是英雄就下100层-开源讲座(一)从天而降

  [复制链接]

该用户从未签到

发表于 2013-4-8 20:40:12 | 显示全部楼层 |阅读模式
是英雄就下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.     }  
复制代码
上面的三个参数中,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. isMirror:Boolean型,当设定为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


































本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2013-4-8 20:40:36 | 显示全部楼层
    不错谢谢楼主分享啊!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2013-5-2 22:00:47 | 显示全部楼层
    顶!

    (开)(发)(票)
    (开)(发)(票)
    (开)(发)(票)呼Tel:135 3814 8810   扣扣_348050196

       


        ,
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-29 22:17 , Processed in 0.440153 second(s), 40 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表