为了应付检查,暂时放博客上了。
小蜜蜂游戏---合作者:任洋,林雅峰
最近分析了一些网页游戏,其实在我们熟知的植物大战僵尸,2048等,个人感觉逻辑复杂在于物体运动,碰撞检测。于是,我只是做比较熟悉儿时玩的小蜜蜂游戏,其实在思路和逻辑判断很像。
游戏分析:
1.数据创建包括敌人数据,关卡设置,战斗机
2.蜜蜂移动
3.操作飞机
4.操作子弹
5.碰撞检测
编程语言:
html+css+javascript 网页游戏
游戏维护上的思考:
采用单体写法:JSON有命名空间,冲突就会降低,更好维护代码
敌人跟随:运动算法
关卡设计:多关计算
其他功能:积分,血量等
游戏代码分析:
一:css模块(样式控制):只是简单布局。
*{ margin:0; padding:0;} li{ list-style:none;} #div1{ width:800px; height:600px; overflow:hidden; background:black; margin:20px auto; position:relative;} #gameBtn{ color:white; font-size:20px; cursor:pointer; border:1px #FFFFFF solid; width:100px; height:30px; line-height:30px; text-align:center; position:absolute; top:285px; left:350px;} #score{ color:#FFFFFF;} #bee{ position:relative;} .enemy1{ width:40px; height:28px; background:url(images/mf1.png) no-repeat; float:left;} .enemy2{ width:40px; height:28px; background:url(images/mf2.png) no-repeat; float:left;} .enemy3{ width:40px; height:28px; background:url(images/mf3.png) no-repeat; float:left;} .air1{ width:46px; height:60px; background:url(images/fj.png) no-repeat; position:absolute;} .bullet{ width:1px; overflow:hidden; height:10px; background:white; position:absolute;}
二:javascript模块
1.数据设置
1.1蜜蜂数据模块 style是不同的蜜蜂,blood血量表示打几次才能消灭,score表示得分
oEnemy : { //敌人的数据 e1 : {style:'enemy1',blood:1,speed:5,score:1}, e2 : {style:'enemy2',blood:2,speed:7,score:2}, e3 : {style:'enemy3',blood:3,speed:10,score:3} }
1.2关卡数据:蜜蜂方阵排列,并设置飞行速度和飞行时间
gk : [ //关卡的数据 { eMap : [ 'e2','e2','e2','e2','e2','e2','e2','e2','e2','e2', 'e2','e2','e2','e2','e2','e2','e2','e2','e2','e2', 'e2','e2','e2','e2','e2','e2','e2','e2','e2','e2', 'e1','e1','e1','e1','e1','e1','e1','e1','e1','e1', 'e1','e1','e1','e1','e1','e1','e1','e1','e1','e1', 'e1','e1','e1','e1','e1','e1','e1','e1','e1','e1' ], colNum : 10, iSpeedX : 10, iSpeedY : 10, times : 2000 }, { eMap : [ 'e3','e3','e3','e3','e3','e3','e3','e3','e3','e3', 'e3','e3','e3','e3','e3','e3','e3','e3','e3','e3', 'e3','e3','e3','e3','e3','e3','e3','e3','e3','e3', 'e1','e1','e1','e1','e1','e1','e1','e1','e1','e1', 'e1','e1','e1','e1','e1','e1','e1','e1','e1','e1', 'e1','e1','e1','e1','e1','e1','e1','e1','e1','e1' ], colNum : 10, iSpeedX : 10, iSpeedY : 10, times : 2000 } ]
1.3战斗机:攻打蜜蜂
air : { //飞机的数据 style : 'air1', bulletStyle : 'bullet' }
2.元素生成:createElement
2.1创建积分,记录分数
createScore : function(){ //创建积分 var oS = document.createElement('div'); oS.id = 'score'; oS.innerHTML = '积分:<span>0</span>分'; this.oParent.appendChild(oS); this.oSNum = oS.getElementsByTagName('span')[0]; }
2.2 创建敌人
createEemey : function(iNow){ //创建敌人 if( this.oUl ){ this.oParent.removeChild( this.oUl ); clearInterval(this.oUl.timer); } document.title = '第'+ (iNow + 1) +'关'; var gk = this.gk[iNow]; var oUl = document.createElement('ul'); this.oUl = oUl; this.aLi = null; var arr = []; oUl.id = 'bee'; oUl.style.width = gk.colNum * 40 + 'px'; this.oParent.appendChild(oUl); oUl.style.left = (this.oParent.offsetWidth - oUl.offsetWidth)/2 + 'px'; for(var i=0;i<gk.eMap.length;i++){ var oLi = document.createElement('li'); oLi.className = this.oEnemy[gk.eMap[i]].style; oLi.blood = this.oEnemy[gk.eMap[i]].blood; oLi.speed = this.oEnemy[gk.eMap[i]].speed; oLi.score = this.oEnemy[gk.eMap[i]].score; oUl.appendChild(oLi); } this.aLi = oUl.getElementsByTagName('li'); for(var i=0;i<this.aLi.length;i++){ arr.push( [ this.aLi[i].offsetLeft , this.aLi[i].offsetTop ] ); } for(var i=0;i<this.aLi.length;i++){ this.aLi[i].style.position = 'absolute'; this.aLi[i].style.left = arr[i][0] + 'px'; this.aLi[i].style.top = arr[i][1] + 'px'; } this.runEnemy(gk); }
2.3创建飞机
createAir : function(){ //创建飞机 var oAir = document.createElement('div'); oAir.className = this.air.style; this.oAir = oAir; this.oParent.appendChild( oAir ); oAir.style.left = (this.oParent.offsetWidth - oAir.offsetWidth)/2 + 'px'; oAir.style.top = this.oParent.offsetHeight - oAir.offsetHeight + 'px'; this.bindAir(); }
2.4创建子弹
createBullet : function(){ //创建子弹 var oB = document.createElement('div'); oB.className = this.air.bulletStyle; this.oParent.appendChild( oB ); oB.style.left = this.oAir.offsetLeft + this.oAir.offsetWidth/2 + 'px'; oB.style.top = this.oAir.offsetTop - 10 + 'px'; this.runBullet(oB); }
3.敌人移动:使用定时器setTimeout setInterval,控制蜜蜂的飞行轨迹
runEnemy : function(gk){ //敌人移动 var This = this; var L = 0; var R = this.oParent.offsetWidth - this.oUl.offsetWidth; this.oUl.timer = setInterval(function(){ if(This.oUl.offsetLeft>R){ gk.iSpeedX *= -1; This.oUl.style.top = This.oUl.offsetTop + gk.iSpeedY + 'px'; } else if(This.oUl.offsetLeft<L){ gk.iSpeedX *= -1; This.oUl.style.top = This.oUl.offsetTop + gk.iSpeedY + 'px'; } This.oUl.style.left = This.oUl.offsetLeft + gk.iSpeedX + 'px'; },200); setInterval(function(){ This.oneMove(); },gk.times); }
4.单兵作战
oneMove : function(){ //单兵作战 var nowLi = this.aLi[ Math.floor(Math.random()*this.aLi.length) ]; var This = this; nowLi.timer = setInterval(function(){ var a = (This.oAir.offsetLeft + This.oAir.offsetWidth/2) - (nowLi.offsetLeft + nowLi.parentNode.offsetLeft + nowLi.offsetWidth/2); var b = (This.oAir.offsetTop + This.oAir.offsetHeight/2) - (nowLi.offsetTop + nowLi.parentNode.offsetTop + nowLi.offsetHeight/2); var c = Math.sqrt(a*a + b*b); var sX = nowLi.speed * a/c; var sY = nowLi.speed * b/c; nowLi.style.left = nowLi.offsetLeft + sX + 'px'; nowLi.style.top = nowLi.offsetTop + sY + 'px'; if( This.pz( This.oAir , nowLi ) ){ alert('游戏结束'); window.location.reload(); } },30); }
5.碰撞检测:方法
pz : function(obj1,obj2){ //碰撞检测 var L1 = obj1.offsetLeft; var R1 = obj1.offsetLeft + obj1.offsetWidth; var T1 = obj1.offsetTop; var B1 = obj1.offsetTop + obj1.offsetHeight; var L2 = obj2.offsetLeft+obj2.parentNode.offsetLeft; var R2 = obj2.offsetLeft + obj2.offsetWidth + obj2.parentNode.offsetLeft; var T2 = obj2.offsetTop + obj2.parentNode.offsetTop;; var B2 = obj2.offsetTop + obj2.offsetHeight + obj2.parentNode.offsetTop; if( R1<L2 || L1>R2 || T1>B2 || B1<T2 ){ return false; } else{ return true; } }
6.操作飞机
bindAir : function(){ //操作飞机 var timer = null; var iNum = 0; var This = this; document.onkeydown = function(ev){ var ev = ev || window.event; if(!timer){ timer = setInterval(show,30); } if( ev.keyCode == 37 ){ iNum = 1; } else if( ev.keyCode == 39 ){ iNum = 2; } }; document.onkeyup = function(ev){ var ev = ev || window.event; clearInterval(timer); timer = null; iNum = 0; if(ev.keyCode == 32){ This.createBullet(); } }; function show(){ if(iNum == 1){ This.oAir.style.left = This.oAir.offsetLeft - 10 + 'px'; } else if(iNum == 2){ This.oAir.style.left = This.oAir.offsetLeft + 10 + 'px'; } } }
7.子弹移动
runBullet : function(oB){ //子弹移动 var This = this; oB.timer = setInterval(function(){ var T = oB.offsetTop - 10; if(T<-10){ clearInterval(oB.timer); This.oParent.removeChild(oB); } else{ oB.style.top = T + 'px'; } for(var i=0;i<This.aLi.length;i++){ if( This.pz(oB,This.aLi[i]) ){ if(This.aLi[i].blood == 1){ clearInterval( This.aLi[i].timer ); This.oSNum.innerHTML = parseInt(This.oSNum.innerHTML) + This.aLi[i].score; This.oUl.removeChild( This.aLi[i] ); } else{ This.aLi[i].blood--; } This.oParent.removeChild(oB); clearInterval(oB.timer); } } if( !This.aLi.length ){ This.createEemey(1); } },30); }
游戏效果图:
总结:
1.在做复杂效果和游戏时,做好注释,有助于开发和后期维护。
2.游戏是一个大的json,所有跟游戏相关的代码放入json中。游戏调用放入init函数。
3.数据和样式分离
4.不用的元素要销毁。
5.一个功能一个函数,不要叠到一起。
6.元素销毁:将不用的元素删除掉。考虑性能
7.offset是相对于有定位的父级,在比较碰撞检测时必须让飞机和小蜜蜂保持在相对的同一个父级检测。
8.小技巧js布局转换:将浮动布局变换为绝对定位。
不足:
因为没有美工设计,在图形界面上有点丑陋。