個人分析javascript 小遊戲 --飛機大戰 (單體單例)
阿新 • • 發佈:2019-02-02
轉載一篇-------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兩種圖片都可以用這一張
本文只是轉載之後