web版canvas作飛機大戰遊戲 總結

  嘮嘮:兩天的時間跟着作了個飛機大戰的遊戲,感受作遊戲挺好的。說是用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 }
View Code

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             ...
View Code
 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 .......
View Code

 

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             }
View Code

 

   繼承實例化:

 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);
View Code

  利用這種方式將全部的對象都進行實例化,並添加相應的方法

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             }
View Code

 

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);
View Code

 

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             }
View Code

 

   3.鼠標離開畫布事件,鼠標離開則遊戲暫停

1             canvas.onmouseout = function(){
2                 if (gameData.state == gameData.RUNNING)
3                 {
4                     gameData.state = gameData.PAUSED;
5                 }
6             }    
View Code

 

8、後續的一些設想

  如今的遊戲不能從新開始,須要刷新才能從新開始,因此定義了 init() 函數用於遊戲結束後從新開始(須要刪除setTimeout事件):

            function init(){
                //設置遊戲的初始狀態
                gameData.state = gameData.START;
                gameData.score = 0;//分數重置
                gameData.heroLife = 3;//聲明值重置
                //遊戲運行
                gameExec();
            }

 

   還有關於子彈的類型的設想: 能夠設置 雙列子彈,散花彈等子彈的類型,子彈可升級,設置子彈的威力等;能夠設置速度的變動等

  有路過的大神能夠看下下邊的源碼,指點下(源碼不長就10kb多點)

9、源碼連接

  完整源碼下載

相關文章
相關標籤/搜索