标签:游戏 小蜜蜂 fc javascript 面向对象
小蜜蜂这么经典的游戏,相信大家在FC红白机里面肯定玩过,你或许忘记了这个游戏的名字,但我相信你若干年之后重新看回这个游戏,一定会唤起童年记忆。这游戏看起来很复杂,但是用JavaScript也可以轻轻松松把它写出来。就像上次的《【JavaScript】贪吃蛇》(点击打开链接)一样,关键是解决好几个核心问题,就能写出来。没用到什么复杂、生疏的方法,还是那句大神级的setInterval。
一、基本目标
写出FC上的小蜜蜂游戏。“蜜蜂”不停地往下飞,你可以发射子弹清空,当“蜜蜂”飞到底层就输了。把所有的“蜜蜂”清空,则刷新一个“蜂群”,当然,这里的“蜂群”我就写了一个,大家可以根据《【JavaScript】打印星型金字塔》(点击打开链接)里面的思想,创造不同的蜂群,“蜂群”就是不同形状的星型金字塔。
二、舞台布局
就是一行文字与两个div而已。“蜂群”稍候用Javascript创建,注意,这里的黑色滑块div是镶嵌在舞台这个div里面的,黑色滑块的left与top是相对于舞台而言的,后面用Javascript创建的“蜂群”也是,具体见《【CSS】关于position:absolute布局》(点击打开链接)。
布局思想见下图:
代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> </head> <body> 小蜜蜂游戏,积分:<span id="point">0</span>,请用←与→或A与D控制方向,F发子弹! <div id="stage" style="position:absolute; left:100px; top:100px; width:400px; height:400px; border:1px solid #000000;" > <div id="div" style="position:absolute; left:180px; top:380px; background-color:#000000; width:20px; height:20px;"></div> </div> </body> </html>
首先,整个游戏分为两大部分,一部分是滑块,其中包括滑块的移动,滑块子弹的发射,子弹的处理,另一部分是蜂群,这一部分简单一点,包括蜂群的创建与蜂群的飘落。
整个游戏有如下的全局变量:
//黑色滑块的初始化 var div=new Div(180,380); //蜜蜂的数目 var beeCount=0; //蜂群是向左移还是向右移 var beeMoveFlag=0; //玩家得分 var point=0; //这个控制蜂群移动的计时器 var beeMoveTimer=0; //这是判断玩家是否已经GameOver了 var loseFlag=0;
先从简单的蜂群说起。
1、蜂群的创建
这里用到了《【JavaScript】打印星型金字塔》(点击打开链接)与《【JavaScript】网页节点的增删改查》(点击打开链接)里面的思想,具体代码如下:
function bee_create(){ //打印一个三角形 for(var i=0;i<7;i++){ for(var j=0;j<i;j++){ var beediv = document.createElement("div"); //这里是要确定最左边的*的起始位置,配合中间位置200px而言 var offsetpx = -20 * i ; beediv.innerHTML = "*"; //40是每个*相隔的像素值 beediv.style.left=200+40*j+offsetpx+"px"; //40也是每行*的行距 beediv.style.top=40*(i-1)+"px"; //定义每个*被击中的有效距离是15x15 beediv.style.width="15px"; beediv.style.height="15px"; //定义每个*的id为beediv1,2,3,...,这样好控制 beediv.id="beediv"+beeCount; //记得设置是绝对定位,否则left与top不起作用 beediv.style.position="absolute"; document.getElementById("stage").appendChild(beediv); beeCount++; } } }
function bee_move(){ //创建一个存放每个*的X,Y坐标的数组,因为JS中没有map就定义两个数组咯。 var beedivYArr=new Array(); var beedivXArr=new Array(); //这里是用来判定蜂群下一次移动是否会越界 var ExistOverFlag=0; for(var i=0;i<beeCount;i++){ //这么长的一段代码只为取走当前*的left与top,因为left与top一开始取出来是个 xx px的字符串,你必须作出一些处理,才能完事。 var beediv_y=parseInt(document.getElementById("beediv"+i).style.top.substring(0,document.getElementById("beediv"+i).style.top.indexOf("px"))); var beediv_x=parseInt(document.getElementById("beediv"+i).style.left.substring(0,document.getElementById("beediv"+i).style.left.indexOf("px"))); //把取到的left与top也就是X,Y放到数组里面的最后一个位置,JavaScript里面的数组就像Java的ArrayList会动态自增的,可以这样放,不是定长数组。 beedivYArr[beedivYArr.length]=beediv_y; beedivXArr[beedivXArr.length]=beediv_x; } for(var i=0;i<beedivXArr.length;i++){ //如果有一只蜜蜂向左或者向右越界则立起相应的flag if(beedivXArr[i]<40){ ExistOverFlag=1; break; } if(beedivXArr[i]>350){ ExistOverFlag=2; break; } } //如果蜜蜂向左越界下一次就向右边移动咯,反之亦然 if(ExistOverFlag==1){ beeMoveFlag=1; } if(ExistOverFlag==2){ beeMoveFlag=0; } for(var i=0;i<beedivYArr.length;i++){ //如果有一只蜜蜂向下越界,玩家就算了,立起相应的flag,一切都结束了 if(beedivYArr[i]>360){ loseFlag=1; break; } //否则,每只蜜蜂向下移10px,如果蜂群是向右移动,那么每只移动向左移动40px,反之依然 beedivYArr[i]=beedivYArr[i]+10; if(beeMoveFlag==0){ beedivXArr[i]=beedivXArr[i]-40; } else{ beedivXArr[i]=beedivXArr[i]+40; } } //更新每一只蜜蜂的位置 for(var i=0;i<beedivYArr.length;i++){ document.getElementById("beediv"+i).style.top=beedivYArr[i]+"px"; document.getElementById("beediv"+i).style.left=beedivXArr[i]+"px"; } //同时检查一下是否有事件发生? game_check(); }
这个非常简单,就两个事件,蜂群是否被玩家清空,蜂群是否向下越界,同时做出相应的处理。
function game_check(){ //如果蜂群被清空,那么再创建蜂群 if(beeCount==0){ bee_create(); } //如果玩家输掉游戏,那么统计玩家的分数,清空计数器,刷新页面让玩家重新开始。 if(loseFlag==1){ var nowPoint=parseInt(document.getElementById("point").innerHTML); alert("Game Over," + "积分:" + nowPoint); clearTimeout(beeMoveTimer); history.go(0); } }
1、滑块移动部分
这个在《【JavaScript】黑点捉红点并躲绿点游戏》(点击打开链接)已经具体里面说过,这里就不再赘述,甚至代码都没有改,只是可以用charCodeAt(0)来取出键值。
首先,是键值处理部分。
document.onkeydown = function(event) { var code; if (window.event) { code = window.event.keyCode; } else { code = event.keyCode; } switch(code){ case 37: div.move_left(); break; case 39: div.move_right(); break; case 65: div.move_left(); break; case 68: div.move_right(); break; //可以直接找出F的键值,charCodeAt(n)能够返回当前字符串的第N个字符的Unicode码 //大写字母的Unicode码与其键值对应,所以F必须要大写 case ("F".charCodeAt(0)): div.fire(); break; } }然后,与《【JavaScript】黑点捉红点并躲绿点游戏》(点击打开链接)同样,为这个滑块开一个类,在里面写出对应的构造函数与响应移动的类函数,如果发现滑块会越界则直接不响应这次移动。
function Div(x,y){ this.x=x; this.y=y; this.move_left=function(){ if(this.x>0){ this.x=this.x-10; document.getElementById("div").style.left=this.x+"px"; } } this.move_right=function(){ if(this.x<380){ this.x=this.x+10; document.getElementById("div").style.left=this.x+"px"; } } }
首先在这个类里面定义作用与这个类的全局变量。
//考虑到玩家很可能一次性发射多个子弹,必须定义一个数组保存玩家的子弹,一个一个地处理 var BulletArr=new Array(); //玩家是否第一次发射子弹? var First=true;
然后,继续为Div类添加相应的子弹发射的类函数。与上面蜂群的创建同样生成子弹,只是这次需要把生成的子弹放到一个数组里面处理。如果不这样做,前一颗子弹没有处理完,用户在后面发生的子弹就会把前面的子弹覆盖,导致程序无法正常运行。
//发子弹 this.fire=function(){ var bullet=document.createElement("div"); bullet.innerHTML="x"; //子弹的初始位置就是滑块的位置 bullet.style.left=this.x+10+"px"; bullet.style.top=this.y+"px"; //其有效范围同样与蜜蜂*范围一样为15x15 bullet.style.width="15px"; bullet.style.height="15px"; //记得设置绝对定位,否则left与top无效 bullet.style.position="absolute"; document.getElementById("stage").appendChild(bullet); //把这个子弹放在数组中,进行管理 BulletArr[BulletArr.length]=bullet; //如果玩家发射子弹之后只有一颗子弹,才调用子弹移动函数。这个子弹移动是整个子弹数组里面的子弹移动,不是单一子弹 //如果每一发射一颗这段都调用这个子弹移动函数,子弹数组的移动会变得越来越快。 if(BulletArr.length==1&&First){ window.setInterval("div.bullet_move()",50); } }
这个函数最为复杂,当然也是最核心的函数,同时也是本工程最后一个函数了。
子弹移动的时候是否碰到蜜蜂,同样是用到了《【JavaScript】黑点捉红点并躲绿点游戏》(点击打开链接)里面的思想,看子弹的有效范围是否与蜜蜂的有效范围重合。取出整个残余蜂群的时候,用到了《【JavaScript】利用getElementsByTagName与getElementsByName改进原生态兼容IE6标签页》(点击打开链接)的方法取出舞台上的所有div,然后对取出的所有div判断哪个的innerHTML是*,就是蜜蜂了,就可以对蜜蜂重新编号了。
this.bullet_move=function bullet_move(){ //首先,一进来就禁止其他子弹再调用这个线程,如果所有子弹都消失,子弹输出长度变成0,由于没有clearTimeout,处理子弹移动的线程依旧存在的。 //再发射子弹,这个线程会自动处理的 First=false; for(var i=0;i<BulletArr.length;i++){ //取出当前子弹的坐标 var bullet=BulletArr[i]; var bullet_y=parseInt(bullet.style.top.substring(0,bullet.style.top.indexOf("px"))); var bullet_x=parseInt(bullet.style.left.substring(0,bullet.style.left.indexOf("px"))); //如果子弹没有到舞台上界 if(bullet_y>0){ //那么向上移动20px bullet.style.top=bullet_y-20+"px"; //同时判断是否碰见蜜蜂 var BulletHitBeeFlag=0; //以下存放蜜蜂坐标的数组 var beedivYArr=new Array(); var beedivXArr=new Array(); //这里是记录第几只蜜蜂被打中的id var beeHited=0; //取出当前所有蜜蜂的坐标,之所以用j来做计算变量,是为了防止与外循环for的计算变量i冲突 for(var j=0;j<beeCount;j++){ var beediv_y=parseInt(document.getElementById("beediv"+j).style.top.substring(0,document.getElementById("beediv"+j).style.top.indexOf("px"))); var beediv_x=parseInt(document.getElementById("beediv"+j).style.left.substring(0,document.getElementById("beediv"+j).style.left.indexOf("px"))); beedivYArr[beedivYArr.length]=beediv_y; beedivXArr[beedivXArr.length]=beediv_x; } //判断是否有蜜蜂被打中 for(var j=0;j<beedivYArr.length;j++){ if((beedivYArr[j]>bullet_y-20)&&(beedivYArr[j]<bullet_y+20)&&(beedivXArr[j]>bullet_x-20)&&(beedivXArr[j]<bullet_x+20)){ BulletHitBeeFlag=1; beeHited=j; break; } } //如果有蜜蜂被打中 if(BulletHitBeeFlag==1){ //在舞台清理那只被打中的蜜蜂 var BeeHitedDiv=document.getElementById("beediv"+beeHited); document.getElementById("stage").removeChild(BeeHitedDiv); //玩家得分+1,并更新得分 point++; document.getElementById("point").innerHTML=point; //下面,对残余蜜蜂的id重新编号,并统计有多少个蜜蜂,beediv1,2,3,4,...配合其他的函数控制,如果出现beediv1,3,4的情况,就不好整 beeCount=0; var BeeExistDivArr=document.getElementById("stage").getElementsByTagName("div"); for(var j=0;j<BeeExistDivArr.length;j++){ if(BeeExistDivArr[j].innerHTML=="*"){ BeeExistDivArr[j].id="beediv"+beeCount; beeCount++; } } } } //如果子弹到达上界 else{ //从数组中取出这个元素,删除 BulletArr.splice(i,1); //找到自己的父节点,把自己删掉 bullet.parentNode.removeChild(bullet); } } }
最后,在一开始调用如下函数,整个游戏就可以跑起来了:
window.onload = function(){ bee_create(); bee_move(); beeMoveTimer = setInterval("bee_move()",1000); }
这个游戏的写作根本就没有用到任何新的内容,新用法,仅仅是以前做过的项目的升华。仅仅是需要注意《【JavaScript】变量冲突是可以通过编译的》(点击打开链接)这个问题就可以了。整个游戏的代码如下,把如下代码拷贝到记事本,保存为.html就可以重温当年在FC红白机上的小蜜蜂游戏了。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> </head> <body> 小蜜蜂游戏,积分:<span id="point">0</span>,请用←与→或A与D控制方向,F发子弹! <div id="stage" style="position:absolute; left:100px; top:100px; width:400px; height:400px; border:1px solid #000000;" > <div id="div" style="position:absolute; left:180px; top:380px; background-color:#000000; width:20px; height:20px;"></div> </div> </body> </html> <script> //黑色滑块的初始化 var div=new Div(180,380); //蜜蜂的数目 var beeCount=0; //蜂群是向左移还是向右移 var beeMoveFlag=0; //玩家得分 var point=0; //这个控制蜂群移动的计时器 var beeMoveTimer=0; //这是判断玩家是否已经GameOver了 var loseFlag=0; function Div(x,y){ this.x=x; this.y=y; //考虑到玩家很可能一次性发射多个子弹,必须定义一个数组保存玩家的子弹,一个一个地处理 var BulletArr=new Array(); //玩家是否第一次发射子弹? var First=true; this.move_left=function(){ if(this.x>0){ this.x=this.x-10; document.getElementById("div").style.left=this.x+"px"; } } this.move_right=function(){ if(this.x<380){ this.x=this.x+10; document.getElementById("div").style.left=this.x+"px"; } } //发子弹 this.fire=function(){ var bullet=document.createElement("div"); bullet.innerHTML="x"; //子弹的初始位置就是滑块的位置 bullet.style.left=this.x+10+"px"; bullet.style.top=this.y+"px"; //其有效范围同样与蜜蜂*范围一样为15x15 bullet.style.width="15px"; bullet.style.height="15px"; //记得设置绝对定位,否则left与top无效 bullet.style.position="absolute"; document.getElementById("stage").appendChild(bullet); //把这个子弹放在数组中,进行管理 BulletArr[BulletArr.length]=bullet; //如果玩家发射子弹之后只有一颗子弹,才调用子弹移动函数。这个子弹移动是整个子弹数组里面的子弹移动,不是单一子弹 //如果每一发射一颗这段都调用这个子弹移动函数,子弹数组的移动会变得越来越快。 if(BulletArr.length==1&&First){ window.setInterval("div.bullet_move()",50); } } //让子弹飞一会 this.bullet_move=function bullet_move(){ //首先,一进来就禁止其他子弹再调用这个线程,如果所有子弹都消失,子弹输出长度变成0,由于没有clearTimeout,处理子弹移动的线程依旧存在的。 //再发射子弹,这个线程会自动处理的 First=false; for(var i=0;i<BulletArr.length;i++){ //取出当前子弹的坐标 var bullet=BulletArr[i]; var bullet_y=parseInt(bullet.style.top.substring(0,bullet.style.top.indexOf("px"))); var bullet_x=parseInt(bullet.style.left.substring(0,bullet.style.left.indexOf("px"))); //如果子弹没有到舞台上界 if(bullet_y>0){ //那么向上移动20px bullet.style.top=bullet_y-20+"px"; //同时判断是否碰见蜜蜂 var BulletHitBeeFlag=0; //以下存放蜜蜂坐标的数组 var beedivYArr=new Array(); var beedivXArr=new Array(); //这里是记录第几只蜜蜂被打中的id var beeHited=0; //取出当前所有蜜蜂的坐标,之所以用j来做计算变量,是为了防止与外循环for的计算变量i冲突 for(var j=0;j<beeCount;j++){ var beediv_y=parseInt(document.getElementById("beediv"+j).style.top.substring(0,document.getElementById("beediv"+j).style.top.indexOf("px"))); var beediv_x=parseInt(document.getElementById("beediv"+j).style.left.substring(0,document.getElementById("beediv"+j).style.left.indexOf("px"))); beedivYArr[beedivYArr.length]=beediv_y; beedivXArr[beedivXArr.length]=beediv_x; } //判断是否有蜜蜂被打中 for(var j=0;j<beedivYArr.length;j++){ if((beedivYArr[j]>bullet_y-20)&&(beedivYArr[j]<bullet_y+20)&&(beedivXArr[j]>bullet_x-20)&&(beedivXArr[j]<bullet_x+20)){ BulletHitBeeFlag=1; beeHited=j; break; } } //如果有蜜蜂被打中 if(BulletHitBeeFlag==1){ //在舞台清理那只被打中的蜜蜂 var BeeHitedDiv=document.getElementById("beediv"+beeHited); document.getElementById("stage").removeChild(BeeHitedDiv); //玩家得分+1,并更新得分 point++; document.getElementById("point").innerHTML=point; //下面,对残余蜜蜂的id重新编号,并统计有多少个蜜蜂,beediv1,2,3,4,...配合其他的函数控制,如果出现beediv1,3,4的情况,就不好整 beeCount=0; var BeeExistDivArr=document.getElementById("stage").getElementsByTagName("div"); for(var j=0;j<BeeExistDivArr.length;j++){ if(BeeExistDivArr[j].innerHTML=="*"){ BeeExistDivArr[j].id="beediv"+beeCount; beeCount++; } } } } //如果子弹到达上界 else{ //从数组中取出这个元素,删除 BulletArr.splice(i,1); //找到自己的父节点,把自己删掉 bullet.parentNode.removeChild(bullet); } } } } window.onload = function(){ bee_create(); bee_move(); beeMoveTimer = setInterval("bee_move()",1000); } function bee_create(){ //打印一个三角形 for(var i=0;i<7;i++){ for(var j=0;j<i;j++){ var beediv = document.createElement("div"); //这里是要确定最左边的*的起始位置,配合中间位置200px而言 var offsetpx = -20 * i ; beediv.innerHTML = "*"; //40是每个*相隔的像素值 beediv.style.left=200+40*j+offsetpx+"px"; //40也是每行*的行距 beediv.style.top=40*(i-1)+"px"; //定义每个*被击中的有效距离是15x15 beediv.style.width="15px"; beediv.style.height="15px"; //定义每个*的id为beediv1,2,3,...,这样好控制 beediv.id="beediv"+beeCount; //记得设置是绝对定位,否则left与top不起作用 beediv.style.position="absolute"; document.getElementById("stage").appendChild(beediv); beeCount++; } } } function bee_move(){ //创建一个存放每个*的X,Y坐标的数组,因为JS中没有map就定义两个数组咯。 var beedivYArr=new Array(); var beedivXArr=new Array(); //这里是用来判定蜂群下一次移动是否会越界 var ExistOverFlag=0; for(var i=0;i<beeCount;i++){ //这么长的一段代码只为取走当前*的left与top,因为left与top一开始取出来是个 xx px的字符串,你必须作出一些处理,才能完事。 var beediv_y=parseInt(document.getElementById("beediv"+i).style.top.substring(0,document.getElementById("beediv"+i).style.top.indexOf("px"))); var beediv_x=parseInt(document.getElementById("beediv"+i).style.left.substring(0,document.getElementById("beediv"+i).style.left.indexOf("px"))); //把取到的left与top也就是X,Y放到数组里面的最后一个位置,JavaScript里面的数组就像Java的ArrayList会动态自增的,可以这样放,不是定长数组。 beedivYArr[beedivYArr.length]=beediv_y; beedivXArr[beedivXArr.length]=beediv_x; } for(var i=0;i<beedivXArr.length;i++){ //如果有一只蜜蜂向左或者向右越界则立起相应的flag if(beedivXArr[i]<40){ ExistOverFlag=1; break; } if(beedivXArr[i]>350){ ExistOverFlag=2; break; } } //如果蜜蜂向左越界下一次就向右边移动咯,反之亦然 if(ExistOverFlag==1){ beeMoveFlag=1; } if(ExistOverFlag==2){ beeMoveFlag=0; } for(var i=0;i<beedivYArr.length;i++){ //如果有一只蜜蜂向下越界,玩家就算了,立起相应的flag,一切都结束了 if(beedivYArr[i]>360){ loseFlag=1; break; } //否则,每只蜜蜂向下移10px,如果蜂群是向右移动,那么每只移动向左移动40px,反之依然 beedivYArr[i]=beedivYArr[i]+10; if(beeMoveFlag==0){ beedivXArr[i]=beedivXArr[i]-40; } else{ beedivXArr[i]=beedivXArr[i]+40; } } //更新每一只蜜蜂的位置 for(var i=0;i<beedivYArr.length;i++){ document.getElementById("beediv"+i).style.top=beedivYArr[i]+"px"; document.getElementById("beediv"+i).style.left=beedivXArr[i]+"px"; } //同时检查一下是否有事件发生? game_check(); } function game_check(){ //如果蜂群被清空,那么再创建蜂群 if(beeCount==0){ bee_create(); } //如果玩家输掉游戏,那么统计玩家的分数,清空计数器,刷新页面让玩家重新开始。 if(loseFlag==1){ var nowPoint=parseInt(document.getElementById("point").innerHTML); alert("Game Over," + "积分:" + nowPoint); clearTimeout(beeMoveTimer); history.go(0); } } document.onkeydown = function(event) { var code; if (window.event) { code = window.event.keyCode; } else { code = event.keyCode; } switch(code){ case 37: div.move_left(); break; case 39: div.move_right(); break; case 65: div.move_left(); break; case 68: div.move_right(); break; //可以直接找出F的键值,charCodeAt(n)能够返回当前字符串的第N个字符的Unicode码 //大写字母的Unicode码与其键值对应,所以F必须要大写 case ("F".charCodeAt(0)): div.fire(); break; } } </script>
标签:游戏 小蜜蜂 fc javascript 面向对象
原文地址:http://blog.csdn.net/yongh701/article/details/43939745