博主的话
这里博主将展示此游戏的html和js部分的代码,主要是对这些代码的讲解,教大家如何编写这样一个简单的 h5小游戏。希望大家在认真看完博主的文章后,不但能编写“是男人就下一百层”,还可以发散思维,编写更多有 趣的小游戏。 如果想要跑程序的话,还需要css代码和图片资源;在js里面还用到了jq和lufylegend框架,这是开源的, 大家可以到网上下载。
对于要css代码和img资源的,下载地址:
https://download.csdn.net/download/qq_43592352/12368545
游戏展示
看图说话
游戏初始界面:
游戏开始:
编程工具介绍
1’ Google浏览器。 我是在Google上跑的游戏,如果大家拿我的文件参照的话,尽量用Google。我做的时候没有考虑兼容性 ,觉得一个小游戏,没必要。 2’VS Code。 这个没什么要求的,我用的是VS Code,只要可以编html、css、js,什么都可以,个人喜好。 3’JQuery和lufylegend插件。 简单的说,它们两个也是js文件。只是被封装起来,方便各种功能的调用。 用的话<script src="js/lufylegend-1.10.1.min.js"></script> <script src="js/jquery-3.3.1.js"></script> 直接在相关的文件里引用就可以了。 4’JQuery介绍 jq简单来说就是对原生js的简化,使js的使用更加方便快捷。 5’lufylegend介绍 lufylegend是一种游戏开发引擎,它是通过html的canvas标签来操作的。里面有一些方法很好用,但是, 它的排版和监听和js一比实在是太麻烦,于是我就抛弃了lufylegend。我的js代码只用了lufylegend一点点的 游戏动作封装的函数。 而且,用lufylegend只是身边正好有一本它的书。个人觉得lufylegend不是最好的游戏引擎。大家对游戏 感兴趣的话,不妨去网上找一些更大众的开源引擎。
游戏代码
<html> <link rel="stylesheet" type="text/css" href="css/index.css"/> <script src="js/lufylegend-1.10.1.min.js"></script> <script src="js/jquery-3.3.1.js"></script> <body> <div id="container"> <div id="game"> <audio id="player" src=""></audio> <div id="info"> <div id="info_life"></div> <div id="info_score"> <div class="info_score_num"><img src="css/img/0.png"></div> <div class="info_score_num"><img src="css/img/0.png"></div> <div class="info_score_num"><img src="css/img/0.png"></div> <div class="info_score_num"><img src="css/img/0.png"></div> </div> </div> <div id="main"> <div id="menu"> <div id="menu_title"><text>是男人就下100层</text></div> <div id="menu_hero"> <div id="menu_hero1"><img src="css/img/left.png"/></div> <div id="menu_hero2"></div> <div id="menu_hero3"><img src="css/img/right.png"/></div> </div> <div id="menu_button"> <button id="menu_button1">开始游戏</button><br/> <button id="menu_button2">排行榜</button> </div> </div> <div id="gamemain"> <div id="hero"></div> <div id="game_bg2"><img src="css/img/game_bg2.png"></div> </div> <div id="ranking"> <text>排行榜</text> <div id="rank_table"> <dl> <dt>排名</dt> <dd>1</dd> <dd>2</dd> <dd>3</dd> <dd>4</dd> <dd>5</dd> </dl> <dl> <dt>英雄大名</dt> <dd></dd> <dd></dd> <dd></dd> <dd></dd> <dd></dd> </dl> <dl> <dt>层数</dt> <dd></dd> <dd></dd> <dd></dd> <dd></dd> <dd></dd> </dl> </div> </div> </div> </div> </div> </body> <script> /**************************便捷函数**************************************/ function getRandom(min,max){//获取在区间[min.max]内的int数 var s; s=parseInt(Math.random()*max+1); while(s<min) { s=parseInt(Math.random()*max+1); } return s; } function onIt(hx,hy,fx,fy){ if(hx<=fx+60&&hx>=fx-32&&hy>=fy-32&&hy<=fy-31) return 1; else return 0; } var shansuoTimes=0; function shansuo(){//闪烁3次 shansuoTimes++; $('#hero').fadeTo(200,0.1); $('#hero').fadeTo(200,1); if(shansuoTimes<=3) setTimeout("shansuo()",400); else shansuoTimes=0; } function sleep(ms){//时间延迟函数 return new Promise(resolve =>setTimeout(resolve,ms)) } async function test() { console.log('Hello') await sleep(1000) console.log('world!') } test(); /**************************基础页面操作设置**************************************/ var hero_href=new Array(),hero_href_key=1; for(var i=1;i<=15;i++){ hero_href[i]="css/hero/"+i+".png"; } //js改变网页页面大小 document.body.style.zoom=.8; //控制menu、gamemain、ranking的显示 $("#menu_button1").click(function(){ $("#menu").css('display','none'); $("#gamemain").css('display','block'); $("#ranking").css('display','none'); heroDie(); init(0,"hero",32,32,main); check(); heroDown(); myfloor(); displayScore(); displayLife(); }) $("#menu_button2").click(function(){ $("#menu").css('display','none'); $("#gamemain").css('display','none'); $("#ranking").css('display','block'); }) //控制英雄的切换 $("#menu_hero1 img").click(function(){ if(hero_href_key>1) hero_href_key--; heroDie(); main(); }) $("#menu_hero3 img").click(function(){ if(hero_href_key<15) hero_href_key++; heroDie(); main(); }) //分数显示 var score_pic=new Array('css/img/0.png','css/img/1.png','css/img/2.png','css/img/3.png','css/img/4.png','css/img/5.png','css/img/6.png','css/img/7.png','css/img/8.png','css/img/9.png',); var score=0; function displayScore(){ var s=score; var score0=s%10; var score1=parseInt(s/10)%10; var score2=parseInt(s/100)%10; var score3=parseInt(s/1000); $(".info_score_num img").eq(3).attr('src',score_pic[score0]); $(".info_score_num img").eq(2).attr('src',score_pic[score1]); $(".info_score_num img").eq(1).attr('src',score_pic[score2]); $(".info_score_num img").eq(0).attr('src',score_pic[score3]); setTimeout('displayScore()',50); } //生命条显示 var deadflag=false; function displayLife(){ isdie(); $("#info_life").css('width',nowHP*8+'px'); if(nowHP<=4&&nowHP>0) $("#info_life").css('background','red'); if(nowHP==0&&deadflag==false) {playMusic(1);deadflag=true;} setTimeout('displayLife()',50); } function playMusic(i) { var player = $("#player")[0]; if(i==1) { player.src='css/sound/dead.mp3'; player.play(); } } /**************************游戏设置**************************************/ /***lufylegend框架封装英雄类*****/ var loader,anime,layer; init(50,"menu_hero2",32,32,main); function main(){ loader=new LLoader(); loader.addEventListener(LEvent.COMPLETE,loadBItmapdata); loader.load(hero_href[hero_href_key],"bitmapData"); } function loadBItmapdata(event){ var bitmapdata=new LBitmapData(loader.content,0,0,64,64); var list=LGlobal.divideCoordinate(128,128,4,4); layer=new LSprite(); addChild(layer); anime=new LAnimation(layer,bitmapdata,list); layer.addEventListener(LEvent.ENTER_FRAME,onframe); } function onframe(){ $(document).keydown(function(event){ if(event.which==39){ anime.setAction(2); } else if(event.which==37){ anime.setAction(1); } }); $(document).keyup(function(event){ anime.setAction(0); }); anime.onframe(); } function heroDie(){ layer.die(); layer.removeAllChild(); } /***封装游戏背景类*****/ var bgHeight=0; function background(){ bgHeight+=2; $("#gamemain").css('background','url("css/img/gamemain_bg.png") 0px '+bgHeight+'px'); if(bgHeight>=550) bgHeight=0;//防止bgHeight过大 setTimeout('background()',50); } background(); /*********封装地板****************/ function floor(){ var that=this; var img=$(new Image()); var floorx=Math.random()*370; var floory=530; this.createFloor1=function(){//地板1类 img.attr({ 'src':'css/img/floor1.png', 'class':'floor', 'relative':0, 'type':1 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.createFloor2=function(){//地板2类 img.attr({ 'src':'css/img/floor2.png', 'class':'floor', 'relative':10, 'type':1 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.createFloor3=function(){//地板3类 img.attr({ 'src':'css/img/floor3.png', 'class':'floor', 'relative':0, 'type':1 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.createFloor4=function(){//地板4类 会消失的地板 img.attr({ 'src':'css/img/floor4in1.png', 'class':'floor', 'relative':0, 'type':2 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.createFloor5=function(){//地板5类 会滚动的地板 img.attr({ 'src':'css/img/floor5.gif', 'id':'floor5', 'class':'floor', 'relative':0, 'type':3 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.run=function(){ if(floory>=-20) { floory-=2; img.css('margin-top',floory+'px'); setTimeout(that.run,20); } else { img.css('display','none'); img.remove(); score++; } } } async function changefloor4($ppp) {//地板4类消失函数 $ppp.attr('src','css/img/floor4in2.png') await sleep(300) $ppp.attr("src","css/img/floor4in3.png") await sleep(300) $ppp.css('display','none'); $ppp.remove(); score++; ontheFloor=false;heroDown();clearTimeout(up); } async function floor5Move1(fx){//地板5类左移英雄 while(position[0]+20>fx){ $('#hero').css('margin-left',position[0]+'px'); position[0]-=2; await sleep(40); } ontheFloor=false;heroDown();clearTimeout(up); } function myfloor(){//创建地板 var ppp=new floor(); if(getRandom(1,5)==1) ppp.createFloor1(); else if(getRandom(1,5)==2) ppp.createFloor2(); else if(getRandom(1,5)==3) ppp.createFloor3(); else if(getRandom(1,5)==4) ppp.createFloor4(); else if(getRandom(1,5)==5) ppp.createFloor5(); setTimeout('myfloor()',500); } /*********封装英雄(未封装原因:lufylegend插件已经生成了英雄)****************/ var position=new Array(0,10);//全局变量,hero的位置坐标 var maxHP=12,nowHP=12;//全局变量,最大HP,现在HP var ontheFloor=false;//全局变量,是否在地板上 var gspeed=2;//全局变量,英雄下落速度,可随游戏时间增加 $(document).keydown(function(event){//对英雄移动的键盘操作 if(event.which==37){ ((position[0]-3)<0)?position[0]=0:position[0]-=3; $("#hero").css('margin-left',position[0]+'px'); } else if(event.which==39){ ((position[0]+3)>398)?position[0]=398:position[0]+=3; $("#hero").css('margin-left',position[0]+'px'); } }); var down,up,move; function heroDown(){//英雄自由下落 position[1]+=gspeed; $("#hero").css('margin-top',position[1]+'px'); down=setTimeout("heroDown()",20); } function heroUp(){//英雄随地板上升,此函数与floor类的run函数数值同步 position[1]-=2; $("#hero").css('margin-top',position[1]+'px'); up=setTimeout("heroUp()",20); } function isdie(){//对英雄向上触碰、向下掉底直接死亡,设置nowHP=0,然后交给‘生命条显示’函数来做英雄死亡后的事件 var y=parseInt($("#hero").css('margin-top')); if(y>=520||y<=9) nowHP=0; } /************************对是否落到地板上进行判断、处理****************************/ var StandX; function check(){ var allfloor=$(".floor"); var n=allfloor.length; for(var i=0;i<=n;i++){ var fx=parseInt(allfloor.eq(i).css("margin-left")); var fy=parseInt(allfloor.eq(i).css("margin-top")); var relativey=parseInt(allfloor.eq(i).attr("relative"));//将木板的relative值转化为int型 var type=parseInt(allfloor.eq(i).attr("type"));//将木板的type值转化为int型 var hx=position[0],hy=position[1]; if(onIt(hx,hy,fx,fy)&&(ontheFloor==false)) { ontheFloor=true; clearTimeout(down); position[1]+=relativey;//每个地板加了一个属性relative,是人物相对于木板的距离,方便带刺木板人物位置摆放 if(relativey==10) {nowHP--;shansuo();} if(type==2){ changefloor4(allfloor.eq(i)); } else if(type==3){ floor5Move1(fx); } heroUp(); StandX=fx; } if((hx<StandX-32||hx>StandX+60)&&(ontheFloor==true)) {ontheFloor=false;heroDown();clearTimeout(up);} } setTimeout("check()",.5); } /************************对排行榜相关数据处理****************************/ /*var fso=new XMLHttpRequest(Scripting.FileSystemObject); var f=fso.createtextfile("data.txt",2,true); f.writeLine("wo shi di yi hang"); */ </script> </html>
代码讲解
我尽量把讲解的重心放在游戏编程思想和js上面。
首先是html的节点结构。无论是编游戏,还是编网页,编程之前做好html节点的树结构是十分重要的事情。
如图:
dom结构大概是这样,方便大家搞清关系。
container
这是一个容器div,背景是截图中的那张山水图片。然后我把这个div居中,其他元素都写在container里面。
game
这也是一个容器div,背景如下:
让game居container的中。
info
这里面会显示生命条和分数。
main
main里面有三个div,这才是核心部分。第一个div是菜单,第二个是游戏主页,第三个是排行榜。
其次是js代码的编写,这是核心。
我们把main的宽高限制在#game(以后的div用#id替代)背景的第三个白色透明框。同样的,#menu,#gamemain,#ranking的宽高也是。
js 第一步 切换div的显示与隐藏
当我们刚开始打开游戏,出现的应该是菜单页面,在点击“开始游戏”“排行榜”之后,会切换到相应的div。即显示相应的div,隐藏其他的div。
//控制menu、gamemain、ranking的显示 $("#menu_button1").click(function(){ $("#menu").css('display','none'); $("#gamemain").css('display','block'); $("#ranking").css('display','none'); }) $("#menu_button2").click(function(){ $("#menu").css('display','none'); $("#gamemain").css('display','none'); $("#ranking").css('display','block'); })
对相应的按钮点击后,对不同的div进行显示和隐藏。
js 第二步 在菜单页面用lufylegend插件封装英雄
/***lufylegend框架封装英雄类*****/ var loader,anime,layer; init(50,"menu_hero2",32,32,main); function main(){ loader=new LLoader(); loader.addEventListener(LEvent.COMPLETE,loadBItmapdata); loader.load(hero_href[hero_href_key],"bitmapData"); } function loadBItmapdata(event){ var bitmapdata=new LBitmapData(loader.content,0,0,64,64); var list=LGlobal.divideCoordinate(128,128,4,4); layer=new LSprite(); addChild(layer); anime=new LAnimation(layer,bitmapdata,list); layer.addEventListener(LEvent.ENTER_FRAME,onframe); } function onframe(){ $(document).keydown(function(event){ if(event.which==39){ anime.setAction(2); } else if(event.which==37){ anime.setAction(1); } }); $(document).keyup(function(event){ anime.setAction(0); }); anime.onframe(); } function heroDie(){ layer.die(); layer.removeAllChild(); }
这里值得注意的是:
init(50,"menu_hero2",32,32,main);
此init()方法表示在#menu_hero2为id的div里面建立一个宽高都为32px的canvas标签,整体速度是50ms一次,回调函数是main()。【建议大家去看一下lufylegend的官方API】
在main()函数中有如下代码:
loader.load(hero_href[hero_href_key],"bitmapData");
【划重点!!!】
这里hero_href[hero_href_key]是一个存放我本地英雄图片url的数组。
在main()函数中又调用了loadBItmapdata()函数。loadBItmapdata()函数里有如下代码:
javascriptvar list=LGlobal.divideCoordinate(128,128,4,4);
【划重点!!!】
这是对图片进行分割。长宽都为128px的图片,进行4x4的分割。如下图。这种RPG小游戏的人物图片都是这样的,经过插件封装后会自动循环播放(这里播放速度就和init()函数里面的参数有关啦)。
如果自己用js代码写的话,不一定可以写出来,而且也没有人家的好。
好了,到这里,lufylegend的使命已经结束了,接下来都是js的功劳了。
js 第三步 在菜单页面实现挑选英雄
带大家理清思路。我们要实现的是#menu、#gamemain、#ranking三部分。现在我们已经把#gamemain、 #ranking的display设置为none了,它们消失了,只有#menu存在,所以我们专心做菜单的业务。
大家回到最上方看一下我菜单的样式,css我就不再说了,很简单的。在英雄两边设置了两个按钮来改变英雄的样式。
这个要怎么实现呢?
var hero_href=new Array(),hero_href_key=1; for(var i=1;i<=15;i++){ hero_href[i]="css/hero/"+i+".png"; } //控制英雄的切换 $("#menu_hero1 img").click(function(){ if(hero_href_key>1) hero_href_key--; heroDie(); main(); }) $("#menu_hero3 img").click(function(){ if(hero_href_key<15) hero_href_key++; heroDie(); main(); })
1’定义一个数组hero_href[]用来存放"css/hero/1.png",“css/hero/2.png”……这样的字符,注意我这里的字符就是我用js访问图片的路径,大家要设置好。
2’定义一个hero_href_key。当点击按钮的时候,hero_href_key会加一或者减一。
3’调用heroDie()函数把页面清空,然后再重新调用main(),但是此时的图片url已经改变,所以英雄会相应改变。
js 第四步 在游戏页面生成英雄
这时候菜单页面已经做完了,我们把#menu的display设为none,#gamemain的display设为block。方便调试, 不然每次都要点击一下“开始游戏”按钮。接下来,我们开始做游戏模块!
同样的,在点击“开始游戏”按钮后,插件会清除画布,并在#hero里面生成英雄。这时,init()的参数速度不能为>0,因为多次调用init,它的速度参数会叠加。
//控制menu、gamemain、ranking的显示 $("#menu_button1").click(function(){ $("#menu").css('display','none'); $("#gamemain").css('display','block'); $("#ranking").css('display','none'); heroDie(); init(0,"hero",32,32,main); })
定义全局变量,position[0]为英雄的x,position[1]为英雄的y;
监听键盘的左键和右键控制英雄左右移动,并且不可以移出#gamemain之外。
var position=new Array(0,10);//全局变量,hero的位置坐标 $(document).keydown(function(event){//对英雄移动的键盘操作 if(event.which==37){ ((position[0]-3)<0)?position[0]=0:position[0]-=3; $("#hero").css('margin-left',position[0]+'px'); } else if(event.which==39){ ((position[0]+3)>398)?position[0]=398:position[0]+=3; $("#hero").css('margin-left',position[0]+'px'); } });
js 第五步 在游戏页面制作滚动的背景
/***封装游戏背景类*****/ var bgHeight=0; function background(){ bgHeight+=2; $("#gamemain").css('background','url("css/img/gamemain_bg.png") 0px '+bgHeight+'px'); if(bgHeight>=550) bgHeight=0;//防止bgHeight过大 setTimeout('background()',50); } background();
这里的技巧主要在css的background上,大家不妨去查一下background的参数。首先,我设置background是可以repeat的(没写默认可以),然后再定义y方向上的偏移量。最后每50ms执行一次其y上的偏移量加2。【值得注意的是,虽然背景图片是一张,但是拼接起来要看不出来分界线才行,要不然滚动也没意义】
js 第六步 在游戏页面添加地板!
/*********封装地板****************/ function floor(){ var that=this; var img=$(new Image()); var floorx=Math.random()*370; var floory=530; this.createFloor1=function(){//地板1类 img.attr({ 'src':'css/img/floor1.png', 'class':'floor', 'relative':0, 'type':1 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.createFloor2=function(){//地板2类 img.attr({ 'src':'css/img/floor2.png', 'class':'floor', 'relative':10, 'type':1 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.createFloor3=function(){//地板3类 img.attr({ 'src':'css/img/floor3.png', 'class':'floor', 'relative':0, 'type':1 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.createFloor4=function(){//地板4类 会消失的地板 img.attr({ 'src':'css/img/floor4in1.png', 'class':'floor', 'relative':0, 'type':2 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.createFloor5=function(){//地板5类 会滚动的地板 img.attr({ 'src':'css/img/floor5.gif', 'id':'floor5', 'class':'floor', 'relative':0, 'type':3 }); img.css({ 'margin-left':floorx+'px', 'margin-top':floory+'px', }); $("#gamemain").append(img); this.run(); } this.run=function(){ if(floory>=-20) { floory-=2; img.css('margin-top',floory+'px'); setTimeout(that.run,20); } else { img.css('display','none'); img.remove(); score++; } } }
首先,我们来封装个地板类。我们把地板的x坐标设为随机,y坐标固定在底部。
然后,不同的createfloor函数,它们的url不同(即图片的样式,是地板还是尖刺还是弹簧……),relative不同(针对尖刺地板,假设图片高是20px,对于一般木板,英雄可以直接站上去,但是带刺的木板,英雄要踩刺,得再往下站一些,所以定义relative相当于木板和英雄的相对距离),type不同(不同类型木板,英雄站上去之后有不同的函数去执行)。
最后,我们让每一个createfloor函数都去执行run函数,来控制木板上升,当木板上升到最上方时,把木板删去,分数+1。
function myfloor(){//创建地板 var ppp=new floor(); if(getRandom(1,5)==1) ppp.createFloor1(); else if(getRandom(1,5)==2) ppp.createFloor2(); else if(getRandom(1,5)==3) ppp.createFloor3(); else if(getRandom(1,5)==4) ppp.createFloor4(); else if(getRandom(1,5)==5) ppp.createFloor5(); setTimeout('myfloor()',500); }
每隔0.5秒随机创建五种木板里的一种出来。
js 第七步 定义英雄上升、下降、死亡函数
首先这里面的数值不是随便设置的,不然没有游戏体验的。
封装出英雄上升,下降,死亡函数。
在踩到地板时上升;脚下没有地板时下降,碰到上方的刺或者掉落判断死亡。
var down,up,move; function heroDown(){//英雄自由下落 position[1]+=gspeed; $("#hero").css('margin-top',position[1]+'px'); down=setTimeout("heroDown()",20); } function heroUp(){//英雄随地板上升,此函数与floor类的run函数数值同步 position[1]-=2; $("#hero").css('margin-top',position[1]+'px'); up=setTimeout("heroUp()",20); } function isdie(){//对英雄向上触碰、向下掉底直接死亡,设置nowHP=0,然后交给‘生命条显示’函数来做英雄死亡后的事件 var y=parseInt($("#hero").css('margin-top')); if(y>=520||y<=9) nowHP=0; }
js 第八步 英雄与地板开始作用
var StandX; function check(){ var allfloor=$(".floor"); var n=allfloor.length; for(var i=0;i<=n;i++){ var fx=parseInt(allfloor.eq(i).css("margin-left")); var fy=parseInt(allfloor.eq(i).css("margin-top")); var relativey=parseInt(allfloor.eq(i).attr("relative"));//将木板的relative值转化为int型 var type=parseInt(allfloor.eq(i).attr("type"));//将木板的type值转化为int型 var hx=position[0],hy=position[1]; if(onIt(hx,hy,fx,fy)&&(ontheFloor==false)) { ontheFloor=true; clearTimeout(down); position[1]+=relativey;//每个地板加了一个属性relative,是人物相对于木板的距离,方便带刺木板人物位置摆放 if(relativey==10) {nowHP--;shansuo();} if(type==2){ changefloor4(allfloor.eq(i)); } else if(type==3){ floor5Move1(fx); } heroUp(); StandX=fx; } if((hx<StandX-32||hx>StandX+60)&&(ontheFloor==true)) {ontheFloor=false;heroDown();clearTimeout(up);} } setTimeout("check()",.5); }
这算是核心代码了。
解释如下:
1,定义一个check函数,每0.5ms执行一次,一秒2000次。 2,每次都干什么事情呢? 每次都获取当前页面存在的地板对象,放在一个数组里面。然后用for循环遍历(暴力方式,所以是小游戏,大游戏 得考虑算法和数据结构优化的)每个对象是不是碰到英雄了,并且ontheFloor这个flag也很重要。 onIt(hx,hy,fx,fy)函数是我刚开始封装的,判断英雄有没有站在地板上。 3,如果在地板上了,调用heroup函数,控制英雄与地板同步上升。之后开始判断是哪个地板。如果relative==10(带 刺木板),那么英雄life-1,并且闪烁三次,并且再向下移动10px才行。如果是type==2(会消失的地板),那 么英雄站上去之后,每隔300ms此地板换一个样式,三次之后木板消失,英雄继续下落。如果是type==3(水平传 送带),那么…… 4,如果英雄脚下没有地板了,那么停止heroup函数,执行herodown。
js 第九步 添加生命条、分数、声音显示
//分数显示 var score_pic=new Array('css/img/0.png','css/img/1.png','css/img/2.png','css/img/3.png','css/img/4.png','css/img/5.png','css/img/6.png','css/img/7.png','css/img/8.png','css/img/9.png',); var score=0; function displayScore(){ var s=score; var score0=s%10; var score1=parseInt(s/10)%10; var score2=parseInt(s/100)%10; var score3=parseInt(s/1000); $(".info_score_num img").eq(3).attr('src',score_pic[score0]); $(".info_score_num img").eq(2).attr('src',score_pic[score1]); $(".info_score_num img").eq(1).attr('src',score_pic[score2]); $(".info_score_num img").eq(0).attr('src',score_pic[score3]); setTimeout('displayScore()',50); } //生命条显示 var deadflag=false; function displayLife(){ isdie(); $("#info_life").css('width',nowHP*8+'px'); if(nowHP<=4&&nowHP>0) $("#info_life").css('background','red'); if(nowHP==0&&deadflag==false) {playMusic(1);deadflag=true;} setTimeout('displayLife()',50); } function playMusic(i) { var player = $("#player")[0]; if(i==1) { player.src='css/sound/dead.mp3'; player.play(); } }
分数显示:
我的分数是用图片显示的。就是获取score后,得到个、十、百、千位的值,然后对应我的数字(艺术字样式)的图片显示出来。和之前英雄的显示类似。
生命条显示:
我把生命分成12份,每少1,生命条的宽度小8.3%,当nowHP小于4,设置生命条颜色为红色。
声音:
当nowHP为0,执行声音函数,播放死亡的音效。
js 第十步 排行榜
排行榜,我有三种方法去实现。但是我这个游戏也不是多人玩的,不想做排行榜。
方法介绍给大家:
1,运用php+mysql。
用php写好之后,把获取的值转递给页面,页面来显示。
但是,php文件必须在xampp目录下才可以运行,意味着,我要把html、js文件都移过去。麻烦。
2,运用txt文本。
大家学c的时候,一定操作过用c来对txt流进行读和写吧。
就是这种思想。
第一,每次游戏结束后,你要对玩家的姓名和分数进行写入。
第二,每次打开排行榜,你要读取txt文本,获取值。因为txt文本的特性,所以读取之后你要进行数据提取稍微麻烦一点点(相信大家领会我的意思)。
3,用js/json文件,存数据。
但是好像只能读不能写。
进行下一个游戏的开发!
总结
虽然引用了一些框架,但是都是浅尝辄止。而且对英雄和地板的判断那一块,都是靠for循环,和时间函数来暴力执行(一秒2000次,我都害怕)。所以多看点算法,数据结构,框架还是很重要的,可以进行代码的优化,使其效率更高、更准确。
继承也是一个很重要的地方。比如地板,我本可以定义一个父类,然后对每种类型的地板进行继承父类,然后重写函数,不但节约代码,效率也高。但是我看了找js的书,也没有找到一种好的办法来继承(因为floor里面还有一个Image对象,我其实操作的是Image对象,但是Image对象是不可以编写定义的),所以只好把所有的地板都放在一个类中,用不同的函数名来区分。