1. 程式人生 > >個人分析javascript 小遊戲 --飛機大戰 (單體單例)

個人分析javascript 小遊戲 --飛機大戰 (單體單例)

轉載一篇-------javascript 小遊戲 –飛機大戰 (單體單例)

最近跟著教學視訊一邊學習一邊做了一個javascript的實戰小遊戲

話不多說 直接附上碼源

<!DOCTYPE HTML>
<html>
    <head>
        <title>please enter your title</title>
        <meta charset="utf-8">
        <meta name="Author" content="潭州學院-阿飛老師">
        <style type='text/css'>
            *{ margin:0; padding:0;font-family:"Microsoft yahei";}
            body{ overflow:hidden;}
        </style>
    </head>
    <body>
        <script type="text/javascript">
        /*單例模式*/

            window.onload = function(){
                //通過載入物件的方式開啟
                Game.exe();
            };

            var Game = {

                //啟動程式
                exe : function(){
                    //設定整個頁面為黑色
                    document.body.style.background = '#000';
                    //建立div盒子節點
                    var oDiv = document.createElement('div');
//給盒子新增id屬性 GameBox
                        oDiv.id = 'GameBox';
//設定盒子樣式
                        oDiv.style.cssText = 'width:300px;height:500px;border:10px solid #fff;margin:50px auto;text-align:center;position:relative;overflow:hidden;';
//將div節點新增到body中  新增節點和刪除節點可以參考手冊
                    document.body.appendChild( oDiv );
//呼叫init初始化遊戲方法
                    this.init();
                },
//定義分數
                score : 0,
//判斷是否結束
                ifEnd : false,

                //初始化
                init : function(){
//將game物件this儲存起來,方便之後用的時候出現this代指不一樣
                    var This = this;
//找id  --GameBox  也就是前面定義div盒子時新增的
                    var oDiv = document.getElementById('GameBox');
//清楚內容,,,,
//介紹一下:innerHTML可以清空裡面的標籤,也可以新增標籤,innerTEXT不能新增標籤(純文字資訊)
                    oDiv.innerHTML = '';
                    Game.score = 0;
                    Game.ifEnd = false;
//建立標題    飛機大戰v1.0  h1標籤及樣式
                    var oH = document.createElement('h1');
                        oH.innerHTML = '飛機大戰v1.0';
                        oH.style.cssText = 'color:#fff;font-size:26px;font-weight:normal;padding-top:50px;';
//新增到遊戲盒子中  id=GameBox
                        oDiv.appendChild( oH );
//通過for迴圈建立一個選項,,,簡單模式,,一般模式,,困難模式,,開掛模式
                    for (var i=0;i<4;i++ )
                    {
//建立p標籤及樣式來當按鈕
                        var oP = document.createElement('p');
                            oP.index = i;
                            oP.style.cssText = 'font-size:14px;color:#000;width:150px;height:40px;margin:50px auto;text-align:center;line-height:40px;background:#fff;cursor:pointer;';
                        var html = '';
//onmouseover、onmouseout和下面兩個用法其實一樣,
//就是一對作用下面所有標籤,包括自己,一對只是作用於自己,其他標籤不管
//p的滑鼠監聽  onmouseenter 移入滑鼠回撥的函式  和onmouseleave 一起使用
                        oP.onmouseenter = function(){
                            this.style.background = '#f60';
                            this.style.color = '#fff';
                        };
//p的滑鼠監聽  onmouseleave 移出滑鼠回撥的函式  和onmouseenter 一起使用
                        oP.onmouseleave = function(){
                            this.style.background = '#fff';
                            this.style.color = '#000';
                        };
//設定點選事件  點選即可開始遊戲,這裡This這就是上面所說需要game物件呼叫start,
//不然這裡用的this就相當於oP這個按鈕物件,,可以通過console檢視
                        oP.onclick = function(e){
//e引數也就是點選事件自帶一個even,可以獲取當前位置 x y對應寬高
                            e = e||window.event;
                            This.start( this.index , oDiv , e );
                        };
//設定按鈕文字   和特殊樣式
                        switch ( i )
                        {
                            case 0:
                                html = '簡單難度';
                                break;
                            case 1:
                                html = '中等難度';
                                break;
                            case 2:
                                html = '困難難度';
                                break;
                            case 3:
                                html = '飛哥附體';
                                oP.style.color = '#f00';
                                oP.style.fontWeight = 'bold';
                                oP.onmouseenter = function(){
                                    this.style.background = '#f60';
                                };
                                oP.onmouseleave = function(){
                                    this.style.background = '#fff';
                                };
                                break;
                        }
//將文字新增到按鈕p上
                        oP.innerHTML = html;
//將按鈕p新增到div中  也就是盒子中
                        oDiv.appendChild(oP);
                    };
                },


                //遊戲開始
                start : function( index , oGameBox , e ){
//開始遊戲 innerHTML清除裡面所有東西  
                    oGameBox.innerHTML = '';
//建立span節點
                    var oS = document.createElement('span');
//新增分數,左上角,left:15px,,top10px,,設定分數
                        oS.innerHTML = this.score;
                        oS.style.cssText = 'position:absolute;left:15px;top:10px;font-size:14px;color:#fff';
//新增到盒子中
                    oGameBox.appendChild( oS );
//獲取飛機 自身  的屬性和方法
                    this.plane( oGameBox , e , index);
//獲取飛機 敵人  的屬性和方法
                    this.enemy( oGameBox , oS , index );
                },

                //關於飛機
                plane : function( oGameBox , e , index ){
//獲取點選按鈕觸發的位置  x座標和y座標相對於瀏覽器
                    var x = e.pageX,
                        y = e.pageY;
//js提供了一個Image物件,等同於document.createElement('img');
                    var oPlane = new Image(); // document.createElement('img');
//設定小飛機圖片及屬性  本身
                        oPlane.src = 'img/plane.png';
                        oPlane.width = 60;
                        oPlane.height = 36;
                        oPlane.id = 'plane';
//飛機需要設定的y 和 x
                    var tY = oGameBox.offsetTop+parseInt(oGameBox.style.borderWidth)+oPlane.height/2;
                    var lX = oGameBox.offsetLeft+parseInt(oGameBox.style.borderWidth)+oPlane.width/2;
//50 10 18= 78
//523  10 30= 563    
//這裡用了一個回撥方法onresize,這個是window的方法,當瀏覽器尺寸傳送變化呼叫  
//用來監聽x變化(寬度)號設定 x值
                    window.onresize = function(){
                        lX = oGameBox.offsetLeft+parseInt(oGameBox.style.borderWidth)+oPlane.width/2;
                    };
//開始遊戲時使用覺對定位將飛機定位在選擇模式的位置上的地圖上
                    var top = y-tY;
                    var left = x-lX;
                        oPlane.style.cssText = 'display:block;position:absolute;top:'+top+'px;left:'+left+'px;';
//新增到盒子中
                    oGameBox.appendChild( oPlane );
//計算飛機能在頁面上的最小值和最大值等 也是通過定位來顯示
                    var leftMin = - oPlane.width/2;
                    var leftMax = oGameBox.clientWidth - oPlane.width/2;
                    var topMin = 0;
                    var topMax = oGameBox.clientHeight - oPlane.height;
//滑鼠在元素上移動時回撥的方法監聽
                    document.onmousemove = function(e){
//先判斷是否結束(或死亡)了
                        if ( !Game.ifEnd )
                        {
                            e = e || window.event;
                            var top = e.pageY - tY;
                            var left = e.pageX - lX;
//這幾句就是判斷  滑鼠在盒子區域內,不能大於最大值,如果大於就取最大,如果小於最小值就取最小,
                            top = Math.min( top , topMax );
                            top = Math.max( top , topMin );
                            left = Math.min( left , leftMax );
                            left = Math.max( left , leftMin );
//設定定位的位置,,也就是飛機跟著滑鼠移動,滑鼠移出去了,飛機就在邊上,不能出去
                            oPlane.style.left = left + 'px';
                            oPlane.style.top = top + 'px';
                        }

                    };
//呼叫飛機子彈  誰呼叫  在那裡顯示  index就是遊戲難度的下標
                    this.biubiubiu( oPlane , oGameBox , index );
                },

                //飛機子彈
                biubiubiu : function( oPlane , oGameBox , index ){
//子彈速度
                    var speed;
                    switch ( index )
                    {
                        case 0:
                            speed = 200;
                            break;
                        case 1:
                            speed = 300;
                            break;
                        case 2:
                            speed = 400;
                            break;
                        case 3:
                            speed = 10;
                            break;
                    }
//this.BiuTimer等同於為biubiubiu函式建立了一個物件,用來找到定時器
//開啟一個定時器,,定時器有兩種,,一種是setInterval(a(),time毫秒)每隔多少時間執行一次函式a()
//另一種setTimeout(a(),1000)則是隻呼叫一次,意思就是 一秒過後呼叫一次a()
                    this.BiuTimer = setInterval( function(){
//建立image物件,來顯示子彈及屬性特徵
                        var oBiu = new Image();
                            oBiu.src = 'img/bullet.png';
                            oBiu.width = 6;
                            oBiu.height = 22;
                            oBiu.className = 'biubiubiu';
//第一個子彈位置,,
//top就是飛機的top位置,減去子彈自身高度,再減去3,能實現子彈在飛機上面3px效果
                        var top = oPlane.offsetTop - oBiu.height + 3;
//獲取子彈left大小,
//飛機的left加上飛機的一般寬度,減去子彈一般的寬度,這樣就能實現,子彈中線和飛機對齊
                        var left = oPlane.offsetLeft + oPlane.width/2 - oBiu.width/2;
                            oBiu.style.cssText = 'position:absolute;top:'+top+'px;left:'+left+'px';
//子彈新增到盒子中
                        oGameBox.appendChild( oBiu );
//為每一顆子彈設定一個定時器  oBiu.timer  不然的話子彈就會一直在原地
                        oBiu.timer = setInterval( function(){
                            if ( !oBiu.parentNode )
                            {
                                clearInterval( oBiu.timer );
                            }
//通過修改top定位值  每次減10px  就能達到類似子彈在往上走的樣子
                            oBiu.style.top = oBiu.offsetTop - 10 + 'px';
//如果子彈到達最上面,則清楚定時器,,不然很浪費記憶體資源
                            if ( oBiu.offsetTop < - oBiu.height )
                            {
                                clearInterval( oBiu.timer );
//移除節點(其中一個子彈)
                                oBiu.parentNode.removeChild( oBiu );
                            }
                        } , 13 );//13則為子彈飛行速度了,,用定時器完成的
//speed 是之前有一個index判斷速度  難度不同速度不同,,值越大,速度越慢,
//可以在頁面測試,f12修改屬性
                    } , speed); //  ******************  子彈速度
                },
                //敵軍
                enemy : function(oGameBox , oS , index){
//判斷遊戲難度 給定速度
                    var a , x;
                    switch ( index )
                    {
                        case 0:
                            a = 1;
                            x = 500;
                            break;
                        case 1:
                            a = 3;
                            x = 300;
                            break;
                        case 2:
                            a = 5;
                            x = 200;
                            break;
                        case 3:
                            a = 5;
                            x = 100;
                            break;
                    }
//建立敵人定時器 this.EnemyTimer,之所以先建立定時器,因為,每次執行,就需要一個敵人,不能就一個

                    this.EnemyTimer = setInterval( function(){
//建立敵人  同建立飛機 自身 一樣
                        var oEnemy = new Image();
                            oEnemy.src = 'img/enemy.png';
                            oEnemy.width = 23;
                            oEnemy.height = 30;

                        var lMin = 0;
                        var lMax = oGameBox.clientWidth - oEnemy.width;
//這裡的隨機,是為了在a的範圍內建立敵人,不然敵人一直從一個地方出來
                        var left = Math.random() * (lMax-lMin) + lMin;
                        oEnemy.style.cssText = 'position:absolute;top:'+(-oEnemy.height)+'px;left:'+left+'px;'
                        oGameBox.appendChild( oEnemy );
//這裡的隨機,是為了隨機一個速度出來
                        var b = Math.random() * a + 1;
//開啟敵人運動的定時器oEnemy.timer
                        oEnemy.timer = setInterval(function(){
//敵人往下運動,每次運動 bpx距離
                            oEnemy.style.top = oEnemy.offsetTop + b + 'px'; // ***********敵軍下落速度 
                            if ( oEnemy.offsetTop >= oGameBox.clientHeight )
                            {
                                clearInterval( oEnemy.timer );
//判斷敵人是否到達最下面,是的話就刪除這個敵人
                                oEnemy.parentNode.removeChild( oEnemy );
                            };
                        },13);

                        //getClass是和子彈的碰撞檢測 返回一個子彈集合
                        var allBiu = Game.getClass('biubiubiu');
//定時器oEnemy.pzBiu 用來檢測子彈和飛機碰撞沒? 
                        oEnemy.pzBiu = setInterval(function(){
//變數子彈集合
                            for (var i=0;i<allBiu.length;i++ )
                            {
//Game.boom判斷子彈和是否敵人碰撞
                                if ( Game.boom( oEnemy , allBiu[i] ) )
                                {
//分數加1
                                    Game.score ++;
                                    oS.innerHTML = Game.score;
//替換為敵人被炸燬的圖片
                                    oEnemy.src = 'img/boom.png';
//清楚當前子彈擊中的敵人和子彈的定時器
                                    clearInterval( oEnemy.pzBiu );
                                    clearInterval( oEnemy.pzPlane );
//移除子彈所在陣列節點
                                    allBiu[i].parentNode.removeChild( allBiu[i] );
                                    setTimeout(function(){
                                        if ( oEnemy.parentNode )
                                        {
//移除敵人節點
                                            oEnemy.parentNode.removeChild( oEnemy );
                                        }
                                    },300);
                                    break;
                                }
                            }
                        },50);

                        //和戰機的碰撞檢測
//和上面子彈差不多,也就是自身飛機 和敵人飛機的檢測
                        var oPlane = document.getElementById('plane');
                        oEnemy.pzPlane = setInterval(function(){
//先判斷是否遊戲結束
                            if ( Game.ifEnd )
                            {
                                clearInterval( oEnemy.pzPlane );
                            }
//判斷是否碰撞
                            if ( Game.boom( oEnemy , oPlane ) )
                            {
                                Game.ifEnd = true;
                                clearInterval( oEnemy.pzPlane );
                                clearInterval( Game.BiuTimer );
                                clearInterval( Game.EnemyTimer );
//兩個飛機碰撞,,遊戲結束,並且兩個飛機圖片都替換成撞毀的圖片
                                oEnemy.src = 'img/boom.png';
                                oPlane.src = 'img/boom2.png';
//開啟一次性定時器setTimeout,前面說過這個  一秒後執行Game的over函式
                                setTimeout(function(){
                                    Game.over( oGameBox );
                                },1000);
                            }
                        },50);
                    } , x );  // *********** 敵軍生成速度
                },

                //碰撞檢測
                boom : function( obj1 , obj2 ){
//假設obj1是敵人飛機  obj2是自己飛機  這裡的y 和 x就是 整個頁面top頂端和left側端到目標的距離
//T1  可以這麼理解,敵人飛機為一個正方形,ti則是上面線的y的距離
//B1  可以理解為,敵人飛機下面線的y距離
//L1  可以理解為,敵人飛機左側到瀏覽器left邊的距離
//。。。。。。。。。。
                    var T1 = obj1.offsetTop;
                    var B1 = T1 + obj1.clientHeight;
                    var L1 = obj1.offsetLeft;
                    var R1 = L1 + obj1.clientWidth;

                    var T2 = obj2.offsetTop;
                    var B2 = T2 + obj2.clientHeight;
                    var L2 = obj2.offsetLeft;
                    var R2 = L2 + obj2.clientWidth;
//R2 < L1 飛機的右邊距離比敵人飛機左邊小,肯定撞不到
//L2 > R1 飛機的左邊距離比敵人飛機右邊遠,肯定撞不到
//B2 < T1 飛機的下邊距離比敵人飛機上邊遠,肯定撞不到
//T2 > B1 飛機的上邊距離比敵人飛機下邊遠,肯定撞不到
                    if ( R2 < L1 || L2 > R1 || B2 < T1 || T2 > B1 )
                    {
                        return false; // 沒撞上
                    }
                    else
                    {
                        return true; // 撞上了
                    }
                },

                //遊戲結束  沒什麼可將的了,,就是清楚頁面,然後新建結束頁面 ,
                //其中重新開始,也就是再呼叫一次Game的init初始化方法
                over : function(oGameBox){
                    oGameBox.innerHTML = '';
                    var oDiv = document.createElement('div');
                        oDiv.style.cssText = 'width:200px;height:400px;margin:50px;background:#fff;';
                    var oT = document.createElement('h3');
                        oT.innerHTML = 'Game Over';
                        oT.style.cssText = 'padding-top:50px;;'
                    var oP1 = document.createElement('p');
                        oP1.innerHTML = '您的得分是:' + '<span style="color:#f00;font-weight:bold;">' + this.score + '</span>';
                        oP1.style.cssText = 'font-size:16px;color:#000';

                    var oRestart = document.createElement('div');
                        oRestart.style.cssText = 'width:100px;height:40px;font-size:14px;text-align:center;line-height:40px;color:#000;background:#990;margin:20px auto;cursor:pointer;';
                        oRestart.innerHTML = '重新開始';
                    oRestart.onclick = function(){
                        Game.init();
                    };

                    oDiv.appendChild( oT );
                    oDiv.appendChild( oP1 );
                    oDiv.appendChild( oRestart );
                    oGameBox.appendChild( oDiv );
                },

//getClass方法  這個方法寫得很好,是我覺得的,遍歷所有的節點,並返回所需要的節點陣列
//getClass方法  雖然外面呼叫的時候只有一個引數,但是這裡面還是補上了
                getClass : function( cName , parent ){
                    parent = parent || document;
                    if ( document.getElementsByClassName )
                    {
                        return parent.getElementsByClassName(cName);
                    }
                    else
                    {
//這個 我是這麼理解的。。獲取當前遊戲的時候所有節點,,返回一個數組   
//通過後面if判斷( if ( arrClass[j] == cName ))是否是自己需要(cName)的元素,新增到陣列中
                        var all = parent.getElementsByTagName('*');
                        var arr = [];
                        for ( var i=0;i<all.length;i++ )
                        {
                            var arrClass = all.className.split(' ');
                            for ( var j=0;j<arrClass.length;j++ )
                            {
//判斷是否是自己需要的name,,,這裡所運用到的就是判斷是否是子彈節點
                                if ( arrClass[j] == cName )
                                {
//push方法就是放陣列中新增一個節點
                                    arr.push( all[i] );
                                    break;
                                }
                            }
                        }
//最後返回獲取到的  例如 獲取到的子彈陣列
                        return arr;
                    }
                },

            };

        </script>
    </body>
</html


 

需要用到的圖片,可以自己設計一下

1.自己的飛機

2.敵人飛機

3.boom兩種圖片都可以用這一張

本文只是轉載之後