用javascript寫星際飛機大戰游戲


在github里看到了個不錯的腳本游戲,決定親自動手來寫,效果如下

 

下面是代碼的思路分享

把整個代碼理解消化確實不容易,但是如果你堅持看完相信你一定會有收獲

如果沒興趣可以直接點擊下面的鏈接 復制代碼 開玩:

http://www.cnblogs.com/demonxian3/p/6241755.html

 

1丶首先准備好素材

游戲的元素有:飛機 敵機 子彈 背景 暫停

 

 

素材的大小可以通過drawImage()來改變其大小,因此不需要太糾結素材多少像素

 

創建一個html文件 和一個js文件

然后開始編輯該html文件

 

2.寫一個畫布:

<canvas id="canvas" width=500 height=500 style="border:1px solid #c3c3c3"></canvas>

 

 

3.獲取畫布對象

canvas = document.getElementById('canvas') cxt = canvas.getContext('2d');

 

 

4.設置畫布屬性

var boxx=0

var boxy=0

var boxwidth=500

var boxheight=500

 

 

 

 **************************畫飛機****************************

 

5.聲明飛機相關的變量

飛機橫坐標 縱坐標 寬度 高度 這些都是為下面的drawImage做准備的

var planex; var planey; var planewidth=60; var planeheight=60; var planeImage = new Image(); planeImage.src="images/hero.jpg";  //引入圖片

 

6.布置飛機初始位置

planex = (boxwidth - planewidth) / 2 //畫布的中央 planey = boxheight - planeheight     //畫布的底端

因為這里的坐標(x,y)指的是飛機左上角的坐標,因此需要把飛機的長度算上

 

 

7.畫出飛機

有了坐標和寬高就可以把飛機畫出來了

cxt.drawImage(planeImage,planex,planey,planewidth,planeheight);

 

現在可以打開網頁測試下,看看飛機是否畫出來了,

如果沒有畫出來,那么請別灰心,耐心的查一下有什么錯誤的地方

如果成功顯示出飛機了那么go on!

 

 

飛機畫出來了但是飛機不會動 

那么怎么能讓飛機動呢? 

改變其坐標!

那么什么時候動呢?

按下鍵盤上的 ↑ ↓ ← → 鍵的時候

我們知道鍵盤有個事件驅動 onkeydown

而這個事件驅動有個屬性keycode 

用這個屬性可以綁定上下左右鍵對應的函數

如下可以看到對應的keycode碼

 

下面是四個我們需要的按鍵的對應碼

左 : 37

上 : 38

右 : 39

下 : 40

 

光有事件驅動onkeydown還不夠,我們還需要實時監聽事件的發生

說的通俗點就是 你在任意時刻去按鍵盤 程序都能夠及時響應

下面這個函數就可以幫我們實時監聽事件

addEventListener()函數

語法

element.addEventListener(event, function, useCapture)
 
參數解釋:
element    表示需要使用該方法的對象 
event        表示監聽什么事件  
function    表示監聽到事件后做出什么響應 
useCapture 表示在捕獲或冒泡執行 默認為false 我們就按照默認來
 
 
聲明一個運動跨度變量 這個變量的作用你馬上就能看到了
var sp=0;

 

 
8.監聽body元素 響應事件
 
下面四個if語句用來判斷飛機是否出界
 
body.addEventListener('keydown',function (event){ switch(event.keyCode){ case 37 : if(planex>boxx){sp=8}else{sp=0}planex-=sp;break; case 38 : if(planey>boxy){sp=8}else{sp=0}planey-=sp;break; case 39 : if((planex+planewidth)<boxwidth){sp=8}else{sp=0}planex+=sp;break; case 40 : if((planey+planeheight)<boxheight){sp=8}else{sp=0}planey+=sp;break; default:break; } },false) 

 

到這里 你可以測試一下飛機是否可以動起來了

當然我會直接告訴你結果----不能動!!

因為上面的事件監聽改變的只是飛機的坐標,但是圖片還在原地

為了讓圖片跟着坐標動起來,我們需要寫一個函數

 

 

9.更新飛機圖片位置函數

function drawplane(){ cxt.clearRect(boxx,boxy,boxwidth,boxheight); //清除所有就元素 cxt.drawImage(planeImage,planex,planey,planewidth,planeheight);  //重新畫出飛機 } var fps                               //其實只是用來調飛機流暢度

var gameTimmer = setInterval (run,1000/fps);      //gameTimer是游戲的總驅動計時器

 

function run(){                           //drawplane函數自動運行
 drawplane();                       } 

 

 **************************畫子彈****************************

 

 10.設置子彈的相關變量 也是為drawImage函數的五個參數所做准備

var bulletx; var bullety; var bulletwidth=10; var bulletheight=10; var bulletImage=new Image(); bulletImage.src="images/bullet.png"

 

 

11.存放子彈的彈夾-----數組

用數組來存放子彈方便我們訪問每個子彈對象

var herobullet; //用來表示單個子彈 var allbullets = new Array(); //用來表示所有子彈 

 

12.設置子彈初始位置

我們希望 每顆子彈的起始位置是隨着飛機而改變的 因此把飛機的變量引進來

bulletx=planex+planewidth/2
 bullety=planey+bulletheight

 

13.聲明子彈的構造函數、

這部分有點難理解 也是本代碼的難點

下面聲明的構造函數是用來制作子彈的

 

function bullet(x,y){ this.x=x; //子彈橫坐標 this.y=y;          //子彈縱坐標 this.islive=true;       //子彈存活屬性

this.timmer=null;     //子彈計時器 用來使得子彈自己運動

    this.run = function run(){ //子彈的運動方法 if(this.islive==false||this.y<-10){ //判斷子彈是否存活或出界 clearInterval(this.timmer); //停止運動    this.islive=false; }else{ this.y-=20           //讓子彈往上飛
    } } }

 

 14.生產子彈

 有了做子彈的秘方 那么就可以開始制造子彈了

 在這里可以使用到我們之前定義的數組存放每顆子彈

function producebullet(){ herobullet = new bullet(bulletx,bullety); //生產子彈 allbullets.push(herobullet); //存放子彈 var timmer = setInterval("allbullets[" + (allbullets.length-1) +"].run()" , 50); //設置子彈子彈運行 這里用到eval可以將字符變為有效方法 allbullets[allbullets.length-1].timmer=timmer; //將自動運行的子彈方法賦予到子彈的屬性 }

 

15.畫出子彈

同飛機的道理相同:光改變坐標是看不出效果,還需要把圖片位置也更新了

function drawbullet(){ for (var i=0;i<allbullets.length;i++){ //遍歷每顆子彈 if(allbullets[i].islive){ //如果子彈掛了 就不需要再畫出來了 cxt.drawImage(bulletImage,allbullets.x,allbullets.y,bulletwidth,bulletheight); } } }

 

 16.讓drawbullet函數自動運行

然后把drawbullet函數 放到之前定義的run函數里 不是子彈的方法

function run(){ drawplane(); drawbullet(); }

 

17.讓子彈自動生產

給生產子彈的函數加個計時器

btimmer = setInterval(producebullet,500)

 

 **************************畫敵機****************************

我們來回顧下畫子彈的步驟

 

設置相關屬性 ->  確定初始坐標 -> 子彈構造函數 ->  生產子彈 -> 畫出子彈 -> 自動生產和繪畫

 

畫敵機的步驟和上面的步驟是一樣的

 

但是有個不同的點 那就是敵機初始的橫坐標應該是隨機的  而縱坐標都是0 (頂部位置)

 

說到隨機 Math.random()函數 是不可以缺少的

但這個只能產生0~1的隨機數

因此 Math.random*500   范圍就是0~500范圍

最后四拾伍入   Math.ceil(Math.random*500);

 

18.設置敵機的相關屬性

 

var enemyx;
var enemyy;
var enemywidth=30
var enemyheight=30
var allenemys = new Arr(); //和子彈一樣 數組用來存放所有敵機
var heroenemy; //用來表示其中單個敵機
var enemyImage= new Image();
enemyImage.src
="images/enemy.png"

 

 

19.敵機構造函數

 

//構造函數
//下面基本上和子彈差不多 就不解釋了
function enemy(x,y){ this.x=x; this.y=y; this.islive=true; this.timmer=null; this.run = function run(){ if (this.islive==false||this.y>boxheight){ clearInterval(this.timmer); this.islive=false; }else{ this.y+=2.5; } } } 

20生產敵機

 

//生產隨機位置的敵機

function produceenemy(){ enemyx=Math.ceil(Math.random()*500); //產生隨機初始位 enemyy=33; //在畫布頂端產生敵機 heroenemy = new enemy(enemyx,enemyy); //生產敵機 allenemys.push(heroenemy); //加入數組 var timmer = setInterval("allenemys[" + (allenemys.length-1) + "].run()"); //啟動run函數並使其自動運行 allenemys[allenemys.length-1].timmer=timmer; //run函數賦予在enemy屬性 } 

 

21畫出敵機

//畫出敵機

function drawenemy(){ for (var i=0;i<allenemys.length;i++){ if(allenemys[i].islive){ cxt.drawImage(enemyImage,allenemys[i].x,allenemys[i].y,enemywidth,enemyheight) } } }

 

 

22自動生產敵機 更新敵機

最后把 drawenemy 加入run函數里  給produeenemy 加個計時器

function run(){ drawplane(); drawbullet(); drawenemy(); }
 
         

etimmer = setInterval(produceenemy,800);

 
        

 

 **************************擊中敵機****************************

飛機 敵機  子彈 都畫好了 而且都可以動起來了 , 現在來寫子彈碰到敵機時敵機消失的規則

 

上圖可以清晰的看出子彈擊中敵機的范圍

擊中條件:

bulletx + bulletwidth > enemyx

bulletx < enemyx + enemywidth

bullety < enemyy + enemyheight

function checkbullet{   for(var i=0;i<allenemys.length;i++){ //遍歷敵機     if (allenemys[i].islive){     var e = allenemys[i]; //獲取敵機對象     }     for(var j=0;j<allbullets.length;j++){ //遍歷       if(allbullets[j].islive){         var b = allbullets[j];         if(b.x+b.width>e.x&&b.x<e.x+e.width&&b.y<e.y+e.height){ //這里使用到上面的規則           b.islive=false; //在構造函數里只要islive的屬性為假 就會停止run函數的計時器           e.islive=false; //因此子彈和敵機相關計時器都被clear掉了           score+=100;  //加分
         }       }     }   } }

 

**************************擊中我機****************************

我機的死亡的規則:

 

 

擊中條件:

enemyx+enemywidth > planex

enemyx < planex + planewidth

enemyy + enemyheight > planey

 

function checkenemy(){   for(var i=0;i<allenemys[i].length;i++){   if(allenemys[i].islive){       var e = allenemys[i];       if(e.x+e.width > planex && e.x < planex + planewidth && e.y + e.height > planey){         e.islive=false;         stop();       }     } } }

 

 **************************停止一切****************************

然后把stop函數寫出來

function stop(){ clearInterval(btimmer);    //停止生產子彈
 clearInterval(etimmer);    //停止生產敵機
 clearInterval(gameTimmer); //停止游戲
 allenemys.length=0;        //初始化
 allbullets.length=0;      //初始化
 show.innerHTML=score;       //統計總分
 score=0; }

 

 **************************啟動一切****************************

然后把checkbullet函數 和checkenemy函數 放到游戲驅動run 里頭

function run(){ drawplane(); //畫飛機 drawenemy(); //畫敵機 drawbullet(); //畫子彈 checkbullet(); //檢查子彈 checkenemy(); //檢查敵機 drawscore();  //實時加分
 }

 

 

最后設置一下加分相關的標簽

這個標簽用來顯示當前分數

<div style="position: absolute;top: 90px;left: 30px;
font-weight: bold;font-size: 40px;color:cornflowerblue"
> <span id="show">0</span></div>

 

 

獲取標簽

show = document.getElementById('show');

 

 

實時計分

function drawscore(){ show.innerHTML=score; }

 

 

當然還可以加一些小細節,比如暫停按鈕 彈出窗口統計得分

還可以玩好玩的,比如飛機無敵 無限子彈 超級子彈 無敵並排子彈 總之你自己想怎么改都行

源代碼:http://www.cnblogs.com/demonxian3/p/6241755.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM