嘮嘮:兩天的時間跟着作了個飛機大戰的遊戲,感受作遊戲挺好的。說是用html5作,發現全都是js。說js裏一切皆爲對象,寫的最多的仍是函數,都是函數調用。對這兩天的代碼作個總結,但願路過的大神指點一下,我對這個遊戲的思路,可改進優化的代碼。html
先說一下游戲的基本內容: 打飛機(不要想歪了),有鼠標控制移動英雄機,子彈自動射擊;敵機從上而下,有三種敵機;前端
先說下HTML代碼(主要就是這一行): html5
<canvas id="canFly" width="480" height="650"></canvas>
1、對這個遊戲的的基本數據狀態作定義canvas
主要包括:數組
遊戲的狀態: 開始狀態 英雄機入場狀態 遊戲進行狀態 暫停狀態 gameOver;得分 英雄機的生命 dom
1 var canvas = document.getElementById("canFly");//獲取canvas元素 2 //建立畫布對象 3 var context = canvas.getContext("2d"); 4 //遊戲的基本數據 5 var gameData = { 6 state : this.START, 7 //遊戲狀態 8 START : 0,//開始界面狀態 9 STARTING : 1,//入場動畫過渡狀態 10 RUNNING : 2,//遊戲運行狀態 11 PAUSED : 3,//暫停 12 GAMEOVER : 4,//遊戲結束 13 //英雄機生命 14 heroLife : 3, 15 //得分 16 score : 0, 17 //畫布寬高 18 HEIGHT : canvas.height 19 }
2、對圖片資源的加載及初始化相關數據ide
1 /*-- 加載遊戲圖片 -------------------------------------------------------------------*/ 2 //背景圖片 3 var bgImg = new Image(); 4 bgImg.src="images/background.png"; 5 //logo圖片 6 var startLogo = new Image(); 7 startLogo.src = "images/start.png"; 8 //加載飛機入場動畫 9 var loadings = []; 10 loadings[0] = new Image(); 11 loadings[0].src="Images/game_loading1.png"; 12 loadings[1] = new Image(); 13 loadings[1].src="Images/game_loading2.png"; 14 loadings[2] = new Image(); 15 loadings[2].src="Images/game_loading3.png"; 16 loadings[3] = new Image(); 17 loadings[3].src="Images/game_loading4.png"; 18 //加載英雄機圖片 19 var heros = []; 20 heros[0] = new Image(); 21 heros[0].src="images/hero1.png"; 22 heros[1] = new Image(); 23 heros[1].src="images/hero2.png"; 24 //英雄機爆破動畫圖片 25 heros[2] = new Image(); 26 heros[2].src="images/hero_blowup_n1.png"; 27 heros[3] = new Image(); 28 heros[3].src="images/hero_blowup_n2.png"; 29 heros[4] = new Image(); 30 heros[4].src="images/hero_blowup_n3.png"; 31 heros[5] = new Image(); 32 heros[5].src="images/hero_blowup_n4.png"; 33 //加載子彈的圖片 34 var bullet = []; 35 bullet[0] = new Image(); 36 bullet[0].src = "images/bullet1.png"; 37 ...
1 /*-- 初始化遊戲內容相關數據 --*/ 2 //初始化遊戲背景圖片數據 3 var SKY = { 4 imgs : bgImg,//背景圖片 5 width : 480,//圖片寬度 6 height : 852 //圖片高度 7 } 8 //初始化英雄機入場動畫圖片數據 9 var LOADING = { 10 imgs : loadings, 11 width : 186,//圖片寬度 12 height : 38,//圖片高度 13 sum : loadings.length //圖片個數 14 } 15 //初始化英雄機的數據 16 var HERO = { 17 imgs : heros, 18 width : 99, 19 height : 124, 20 sum : heros.length, 21 length : 2//我方飛機正常圖片個數 22 } 23 //初始化子彈的數據 24 var BULLET = {//默認子彈 25 imgs : bullet, 26 width : 9, 27 height : 21, 28 sum : bullet.length 29 } 30 .......
3、公用構造器及對象實例化函數
定義一個公用的構造器函數,這是我寫這個遊戲認最大的收穫了,在這裏體會到了面向對象的思想;至關於定義一個基礎類,全部的構造器都用公用構造器函數進行初始化,提升代碼的複用,然而在個人優化過程當中僅僅只是節省了50多行的代碼。優化
公共構造器函數:在這裏定義了圖片的寬高,圖片對象是否執行爆破,是否刪除,圖片繪製座標等一些公共的屬性和方法動畫
1 /*-- 通用構造器對象 前端代碼儘可能地使用通用代碼 -------------------------------------------------------------------------------------------------------*/ 2 function Compant(config){ 3 //加載圖片 4 this.imgs = config.imgs; 5 //圖片的寬度和高度 6 this.width = config.width; 7 this.height = config.height; 8 this.sum = config.sum; 9 this.length = config.length; 10 // 敵方飛機具備如下屬性 11 this.type = config.type;//敵機類型 12 this.life = config.life;//敵機聲明值 13 this.score = config.score;//敵機分數 14 // 設置相對速度 15 this.time = 0; 16 // 設置圖片的索引值 17 this.index = 0; 18 // 是否執行爆破動畫的標識 19 this.down = false; 20 // 是否刪除標識 21 this.canDelete = false; 22 //繪圖座標 23 this.x = 0; 24 this.y = 0; 25 // 繪製方法 26 this.paint = function(){ 27 context.drawImage(this.imgs[this.index],this.x,this.y); 28 } 29 // 移動方法 30 this.step = function(){} 31 // 執行撞擊後的邏輯方法 32 this.bang = function(){} 33 }
繼承實例化:
1 //---背景 2 //建立背景圖片的構造器 3 function BgSky(config){ 4 //調用通用構造器初始化 5 Compant.call(this,config); 6 //圖片繪製高度變量 7 this.y1 = -this.height; 8 this.y2 = 0; 9 //定義繪製方法 10 this.paint = function(){ 11 context.drawImage(this.imgs,0,this.y1);//第一張圖片 12 context.drawImage(this.imgs,0,this.y2);//第二張圖片 13 } 14 //背景heigth運動方法 15 this.step = function(){ 16 this.time++; 17 if (this.time%3==0) 18 {//控制背景圖片height值的增長 19 this.y1++;//圖片運動下一幀 20 this.y2++; 21 //圖片移動處畫布後將y座標重置爲-height 實現圖片銜接滾動 22 this.y1>this.height&&(this.y1 = -this.height); 23 this.y2>this.height&&(this.y2 = -this.height); 24 this.time=1;//重置移動時間 25 } 26 } 27 } 28 //建立圖片對象 29 var sky = new BgSky(SKY); 30 31 //---英雄機入場動畫構造器 32 function Loading(config){ 33 Compant.call(this,config); 34 //定義繪製 35 this.paint = function(){ 36 //繪製飛機入場動畫圖片 37 context.drawImage(this.imgs[this.index],0,gameData.HEIGHT-this.height); 38 } 39 //定義入場動畫 40 this.step = function(){ 41 this.time++; 42 if (this.time%20==0) 43 {//實現動畫的播放速度 44 this.index++;//下一幀動畫 45 if (this.index==this.sum) 46 {//判斷動畫結束後,更改遊戲的狀態,進入第三階段遊戲階段 47 gameData.state=gameData.RUNNING; 48 this.time=0;//重置動畫時間 49 } 50 } 51 } 52 } 53 //建立飛機入場動畫的對象 54 var loading = new Loading(LOADING);
利用這種方式將全部的對象都進行實例化,並添加相應的方法
4、英雄機的子彈發射
英雄機的子彈發射是自動,就是說只要控制好裝彈的頻率就能夠了;英雄機發射子彈就是向子彈數組中添加子彈
bullets[bullets.length] = new Bullet(BULLET);;//向子彈數組中添加子彈
子彈的移動,撞擊,刪除等功能在子彈的構造函數中定義,英雄機只管裝彈的頻率;
子彈的繪製:
1 function paintBullets(){ 2 for (var i=0, length=bullets.length; i<length; i++) 3 { 4 bullets[i].paint();//繪製當前子彈 5 if (gameData.state==gameData.RUNNING) 6 {//遊戲運行中時移動子彈 7 bullets[i].step();//移動子彈 8 } 9 } 10 }
刪除子彈的判斷:
1 function clearStep(){ 2 for (var i = bullets.length-1; i>=0 ; i--) 3 { 4 if (bullets[i].y<=-bullets[i].height || (bullets[i].canDelete)) 5 { 6 bullets.splice(i,1);//刪除當前超出屏幕的子彈和撞機的子彈 7 } 8 } 9 }
//這個函數能夠跟上邊的合併到一塊兒
5、敵機的相關設置
敵機的建立: 應爲有三種類型的敵機,按照概率小的最多,中飛機的其次,打飛機滿屏只能有一個
1 //建立用於建立敵方飛機的函數 2 function createEnemies(){ 3 /*建立敵方飛機 - 小,中,大*/ 4 var num = Math.floor(Math.random()*100); 5 if (num < 80) 6 {//小飛機 7 enemies[enemies.length] = new Enemy(ENEMY1); 8 }else if (num < 90) 9 {//中飛機 10 enemies[enemies.length] = new Enemy(ENEMY2); 11 }else { 12 //大飛機只能存在一個 13 if (enemies.length > 0 && enemies[0].type != 2) 14 { 15 enemies.unshift(new Enemy(ENEMY3));//將大飛機添加到數組開頭,這樣每次判斷數組第一個就能夠知道 16 } 17 } 18 }
對敵機的繪製,檢測敵機是否超出屏幕,是否被打中,是否須要爆炸,是否和英雄機相撞等
1 function paintEnemiesAndCheckHit(){ 2 for (var i=0; i<enemies.length; i++) 3 {//遍歷敵機 4 // 5 var enemy = enemies[i];//敵機 6 //檢測敵機和英雄機是否碰撞 7 if ((enemy.y > gameData.HEIGHT)||(enemy.canDelete)) 8 { 9 enemies.splice(i,1);//刪除當前超出屏幕的飛機 10 continue; 11 } 12 enemy.paint();//繪製飛機 13 if (gameData.state == gameData.RUNNING) 14 {//遊戲運行中時才移動飛機 15 enemy.step();//移動飛機 16 } 17 //判斷是否和我方飛機碰撞 18 if (enemy&&enemy.hit(hero)) 19 {//敵機和我方飛機相撞 20 enemy.bang(); 21 hero.bang();//飛機銷燬 22 } 23 //判斷子彈 24 for (var j=0; j<bullets.length; j++) 25 {//子彈遍歷 26 var bullet = bullets[j];//子彈 27 if (enemy.hit(bullet)) 28 {//子彈撞機敵方飛機 29 enemy.bang();//刪除敵機 30 bullet.bang();//刪除子彈 31 } 32 } 33 } 34 }
6、主體流程的控制
這裏使用switch來控制在執行相應狀態的操做,使用setTimeout來控制循環的進行,感受setTimeout比setInterval更加的容易控制
1 //根據遊戲狀態執行相應操做 2 switch (gameData.state) 3 { 4 case gameData.START://遊戲開始狀態 5 context.drawImage(startLogo,30,0);//繪製開始logo 6 break; 7 case gameData.STARTING: //英雄機進場過渡狀態 8 loading.paint();//繪製飛機入場動畫 9 loading.step();//入場動畫 10 break; 11 case gameData.RUNNING: //遊戲進行狀態 12 hero.paint(); 13 hero.step(); 14 hero.shoot();//飛機射擊 15 paintBullets();//繪製全部子彈 16 clearStep();//清除超出的子彈 17 18 if (enemyTime%100 == 0) 19 { 20 createEnemies();//建立敵方飛機 21 } 22 paintEnemiesAndCheckHit();//繪製全部敵方飛機和碰撞檢測 23 break; 24 case gameData.PAUSED: //遊戲暫停狀態 25 hero.paint(); 26 paintBullets();//繪製全部子彈 27 paintEnemiesAndCheckHit();//繪製全部敵方飛機和碰撞檢測 28 paintPaused(); 29 break; 30 case gameData.GAMEOVER: //遊戲結束狀態 31 gameover(); 32 break; 33 } 34 painText();//繪製得分 35 36 //定時器,畫布刷新 37 setTimeout(function(){ 38 gameExec(); 39 },10);
7、響應事件的綁定
1.開始界面單擊鼠標,開始遊戲
1 canvas.onclick = function(){ 2 if (gameData.state == gameData.START) 3 {//在遊戲開始狀態下單擊,進入遊戲過渡階段 4 gameData.state = gameData.STARTING;//改變遊戲狀態 5 } 6 }
2.綁定鼠標的移動事件,英雄機是跟隨鼠標移動的
1 canvas.onmousemove = function(event){ 2 //獲取鼠標當前相對於canvas畫布的座標 3 var x = event.offsetX; 4 var y = event.offsetY; 5 //我方飛機座標設置 6 hero.x=x-hero.width/2;// x座標 7 hero.y=y-hero.height/2;//y座標 8 if (gameData.state == gameData.PAUSED) 9 { 10 gameData.state = gameData.RUNNING; 11 } 12 }
3.鼠標離開畫布事件,鼠標離開則遊戲暫停
1 canvas.onmouseout = function(){ 2 if (gameData.state == gameData.RUNNING) 3 { 4 gameData.state = gameData.PAUSED; 5 } 6 }
8、後續的一些設想
如今的遊戲不能從新開始,須要刷新才能從新開始,因此定義了 init() 函數用於遊戲結束後從新開始(須要刪除setTimeout事件):
function init(){ //設置遊戲的初始狀態 gameData.state = gameData.START; gameData.score = 0;//分數重置 gameData.heroLife = 3;//聲明值重置 //遊戲運行 gameExec(); }
還有關於子彈的類型的設想: 能夠設置 雙列子彈,散花彈等子彈的類型,子彈可升級,設置子彈的威力等;能夠設置速度的變動等
有路過的大神能夠看下下邊的源碼,指點下(源碼不長就10kb多點)
9、源碼連接