JS原生编写飞机大战小蜜蜂游戏

来源:互联网 发布:俄罗斯交友软件vk 编辑:程序博客网 时间:2024/05/28 04:55

javascript设计模式之单体模式--飞机大战小蜜蜂游戏

单体是一个用来划分命名空间并将一批相关的属性和方法组织在一起的对象,如果他可以被实例化,那么他只能被实例化一次。

单体模式是javascript里面最基本但是也是最有用的也是最常用的模式之一。

单体模式的特点:

1,可以用来划分命名空间,从而清除全局变量所带来的危险

2,利用分支技术来封装浏览器直接的差异。

3,可以把代码组织的更为一体,便于阅读和维护。

 

单体模式的思路是:

一个类能返回一个对象的引用(并且永远是同一个)和一个获得该实例的方法(静态方法,通常使用getInstance名称)。那么当我们调用这个方法时,如果类持有的引用不为空就返回该引用,否者就创建该类的实例,并且将实例引用赋值给该类保持的那个引用再返回。同时将该类的构造函数定义为私有方法,避免其他函数使用该构造函数来实例化对象,只通过该类的静态方法来得到该类的唯一实例。


游戏中的困扰:

1.飞机移动的同时可以发射子弹--解决办法:在onkeydown中添加左右移动事件,在onkeyup中添加子弹发射事件和判断是否是移动键移松开,如果是就让移动失效,这样就可以按下飞机移动键的同时,按下子弹发射键并松开此键发射子弹,此时飞机仍然移动。



源码中用到的图片:

飞机--     低级小蜜蜂--    中级小蜜蜂--    高级小蜜蜂--

源代码:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style>
*{ margin:0; padding:0;}
li{ list-style:none;}
#div1{ width:800px; height:600px; overflow:hidden; background:black; margin:20px auto; position:relative;}
#gameName{color:white;font-size:40px;font-family:'华文隶书';position:absolute;top:40px;left:255px;}
#gameAuthor{color:white;font-size:14px;position:absolute;top:578px;left:170px;}
#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;}
</style>

<script>
window.onload=function(){
    var oBtn=document.getElementById("gameBtn");
    oBtn.onclick=function(){
        this.style.display='none';
        document.getElementById('gameAuthor').style.display='none';
        document.getElementById('gameName').style.display='none';
        Game.init('div1');//游戏开始
    };
};

var Game={
    
    oEnemy:{//敌人的数据
        e1:{style:'enemy1',blood:1,speed:3,score:1},
        e2:{style:'enemy2',blood:2,speed:4,score:2},
        e3:{style:'enemy3',blood:3,speed:4,score:3},
    },
    
    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//小蜜蜂飞下来的时间间
        }
    ],
    
    air:{//飞机的数据
        style:'air1',//飞机样式
        bulletStyle:'bullet'//子弹样式
    },
    
    init:function(id){//初始化
        this.oParent=document.getElementById(id);
        
        this.createScore();//创建积分
        
        this.createEnemy(0);//创建敌人
        
        this.createAir();//创建飞机
    },
    
    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];
    },
    
    createEnemy:function(iNow){//敌人的创建
    
        if(this.oUl){//如果敌人整体的ul还存在就把它删掉
            clearInterval(this.oUl.timer);//清除敌人整体移动的定时器
            this.oParent.removeChild(this.oUl);
        }
        
        document.title='第'+(iNow+1)+'关';
    
        var gk=this.gk[iNow];//得到关卡
        var arr=[];//用来存储ul li蜜蜂的top、left值
        var oUl=document.createElement('ul');
        oUl.id='bee';
        oUl.style.width=gk.colNum*40+'px';
        this.oParent.appendChild(oUl);
        oUl.style.left=(this.oParent.offsetWidth-oUl.offsetWidth)/2+'px';
        
        this.oUl=oUl;//让oUl变成对象的属性
        
        for(var i=0;i<gk.eMap.length;i++){//创建li小蜜蜂
            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);//每个蜜蜂填到ul中
        }
        this.aLi=oUl.getElementsByTagName('li');//将所有li小蜜蜂设置为全局的
        
        for(var i=0;i<this.aLi.length;i++){
            arr.push([this.aLi[i].offsetLeft,this.aLi[i].offsetTop]);//arr[][]
        }
        
        //每个蜜蜂转定位
        for(var i=0;i<this.aLi.length;i++){
            //创建蜜蜂存好每个蜜蜂的left、top值后再用JS把ul li蜜蜂原来的浮动改为绝对定位,这样避免了:子弹碰到一个蜜蜂,该蜜蜂消失,而该蜜蜂的相邻蜜蜂因为浮动而来补位又和子弹碰撞,又消失
            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);//敌人整体移动,创建好敌人后就触发
    },
    
    runEnemy:function(gk){//敌人整体移动

        var This=this;
        
        var L=0;
        var R=this.oParent.offsetWidth-this.oUl.offsetWidth;//父层的宽减去ul(敌人整体)的宽就是ul能到达的最大值
        
        this.oUl.timer=setInterval(function(){//定时器赋给此timer方便在通关后销毁
            
            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);//200毫秒移动一次
        
        setInterval(function(){
            This.oneMove();
        },gk.times);//每隔一段时间就有一个蜜蜂移动
    },
    
    oneMove:function(){//单兵作战:一个小蜜蜂移动
        var nowLi=this.aLi[Math.floor(Math.random()*this.aLi.length-1)];//范围内随机数取整用来做当前小蜜蜂的脚标
        var This=this;
        
        nowLi.timer=setInterval(function(){//小蜜蜂被删掉了但是此定时器还在就会出问题,所以这里赋给timer,在子弹删掉蜜蜂前可清除此定时器
            var a=(This.oA.offsetLeft+This.oA.offsetWidth/2)-(nowLi.offsetLeft+nowLi.parentNode.offsetLeft+This.oA.offsetWidth/2);//蜜蜂和飞机中心点的水平距离
            var b=(This.oA.offsetTop+This.oA.offsetHeight/2)-(nowLi.offsetTop+nowLi.parentNode.offsetTop+This.oA.offsetHeight/2);//蜜蜂和飞机中心点的垂直距离
            var c=Math.sqrt(a*a+b*b);//这是实际距离
            
            var iSX=nowLi.speed*a/c;//蜜蜂向飞机靠近的水平速度
            var iSY=nowLi.speed*b/c;//蜜蜂向飞机靠近的垂直速度
            
            nowLi.style.left=nowLi.offsetLeft+iSX+'px';
            nowLi.style.top=nowLi.offsetTop+iSY+'px';
            
            if(This.pz(This.oA,nowLi)){
                alert('游戏结束');
                window.location.reload();
            }
        },30);
    },
    
    createAir:function(){//创建飞机
        var oA=document.createElement('div');
        oA.className=this.air.style;
        
        this.oA=oA;
        
        this.oParent.appendChild(oA);
        oA.style.left=(this.oParent.offsetWidth-oA.offsetWidth)/2+'px';
        oA.style.top=(this.oParent.offsetHeight-oA.offsetHeight)+'px';
        this.bindAir();
    },
    
    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);//把飞机左右移动的定时器赋给timer方便销毁
            }
            
            if(ev.keyCode==37){//左键
                iNum=1;
            }else if(ev.keyCode==39){//右键
                iNum=2;
            }
        };
        
        document.onkeyup=function(ev){//松开按键后的处理
            var ev=ev||window.event;
            if(ev.keyCode==37||ev.keyCode==39){//若松开左右键则取消对应的移动功能
                clearInterval(timer);
                timer=null;
                iNum=0;
            }
            if(ev.keyCode == 32){//空格
                This.createBullet();//创建子弹
            }
        }
        
        function show(){
            if(iNum == 1){
                if(This.oA.style.left == -3 + 'px'){//防止飞机移出游戏窗
                    return false;
                }else{
                    This.oA.style.left = This.oA.offsetLeft - 10 + 'px';
                }
            }else if(iNum == 2){
                if(This.oA.style.left == 757 + 'px'){//防止飞机移出游戏窗
                    return false;
                }else{
                    This.oA.style.left = This.oA.offsetLeft + 10 + 'px';
                }
            }
        }
    },
    
    createBullet:function(){
            //子弹的left值=飞机的left值+飞机本身宽度的一半
            //子弹的top值=飞机的top值-子弹本身的高度
            var oB=document.createElement('div');
            oB.className=this.air.bulletStyle;
            this.oParent.appendChild(oB);
            oB.style.left=this.oA.offsetLeft+this.oA.offsetWidth/2+'px';
            oB.style.top=this.oA.offsetTop-10+'px';
            
            this.runBullet(oB);
    },
    
    runBullet:function(oB){//子弹运动
        var This=this;
        
        oB.timer=setInterval(function(){
            
            if(oB.offsetTop<-10){//当子弹飞出游戏窗就销毁该子弹,谨防子弹一直飞,导致子弹过多,页面元素过多影响性能
                clearInterval(oB.timer);
                This.oParent.removeChild(oB);
            }else{
                oB.style.top=oB.offsetTop-10+'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--;
                    }
                    
                    clearInterval(oB.timer);//先把定时器关闭再删子弹,这样可提高性能
                    This.oParent.removeChild(oB);//删掉碰撞的子弹
                }
            }
            
            if(!This.aLi.length){//如果敌人被打完(li的数组长度为0),就进入下一关
                This.createEnemy(1);
            }
            
        },30);
    },
    
    pz:function(obj1,obj2){//封装好碰撞检测,可实现多对多碰撞检测
        var L1=obj1.offsetLeft;
        var R1=obj1.offsetLeft+obj1.offsetWidth;
        var T1=obj1.offsetTop;
        var B1=obj1.offsetTop+obj1.offsetHeight;
        
        //因为小蜜蜂li是装在ul里面的,所以计算小蜜蜂的top、left值是相对于ul的,所以要加上ul的top、left值才算小蜜蜂的值
        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||B1<T2||T1>B2){
            return false;
        }else{
            return true;
        }
    }
};
</script>
</head>
<body>
<div id="div1">
    <div id="gameName">飞机大战小蜜蜂</div>
    <div id="gameBtn">开始游戏</div>
    <div id="gameAuthor">@copyright 2015&emsp;|&emsp;免责声明:本游戏Johnny出品,如有雷同纯属巧合!</div>
</div>
</body>
</html>

0 0