在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.設置畫布屬性
**************************畫飛機****************************
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()函數
語法
var sp=0;
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函數里 不是子彈的方法
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 加個計時器
**************************擊中敵機****************************
飛機 敵機 子彈 都畫好了 而且都可以動起來了 , 現在來寫子彈碰到敵機時敵機消失的規則
上圖可以清晰的看出子彈擊中敵機的范圍
擊中條件:
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