運用html5 canvas做飛機大戰遊戲(1)
1、首先,寫出canvas前提,定義所需要的變數,如寬高、分數、生命值等。
<div style="text-align: center;"> <canvas id="canvas" width="480px" height="640px"></canvas> </div> <script> var canvas = document.getElementById("canvas"); var gj = canvas.getContext("2d");// 定義遊戲的五種狀態,記錄分數、生命值等相關資料。 const START = 0; var LOADING = 1; var RUNNING = 2; var PAUSE = 3; var GAMEOVER = 4; var state = START; var wid = canvas.width; var hei = canvas.height; var score = 0;var life = 3;
2、定義背景圖片及開始狀態:
由於我們設定的背景是動態向下滾動的,所以這裡先獲取我們所需要的圖片,然後將圖片所具有的一些屬性封裝為一個物件方面後面呼叫。
然後定義一個背景圖片的建構函式,裡面傳入之前定義好的物件,然後用this將引數轉換成函式內屬性,接著畫出圖片並規定圖片向下滾動的方式。
然後將這個建構函式儲存為一個物件,設定定時器呼叫此物件裡的函式方法實現背景圖片的持續滾動狀態。
然後設定一個canvas的點選事件,使其點選之後進入下一個階段,也就是遊戲載入中的loading狀態。
// 定義背景圖片的建構函式function backgroung(images){ this.img = images.img; this.width = images.width; this.height = images.height; this.x1 = 0; this.y1 = 0; this.x2 = 0; this.y2 = -this.height; this.paint = function(){ gj.drawImage(this.img,this.x1,this.y1); gj.drawImage(this.img,this.x2,this.y2); } this.step = function(){ this.y1++; this.y2++; if (this.y1 == this.height) { this.y1 = -this.height; } if (this.y2 == this.height) { this.y2 = -this.height; } } } var load = new backgroung(BG); // 繪出logo var logo = new Image(); logo.src="img/start.png"; // 給canvas一個點選事件,當處於開始狀態的時候點選進入loading狀態 canvas.onclick = function () { if (state == START) { state = LOADING; } }
setInterval( function (){ load.paint(); load.step(); if (state == START) { gj.drawImage(logo,40,0) } else if (state == LOADING) { wait.paint(); wait.step(); } else if (state == RUNNING) { heroes.paint(); heroes.step(); heroes.shoot(); bulletsPaint(); bulletsStep(); bulletsDel(); // console.log(bullets); } else if (state == PAUSE) { } else if (state == GAMEOVER) { } },50 )
3、繪製loading畫面:
loading畫面的實現是利用四張圖片來形成的動態效果,所以將這四張圖片裝入一個數組中以便呼叫。
同樣的用物件來儲存其包含的屬性。
// 定義loading圖片,用陣列包含方便呼叫切換 var loadings = []; loadings[0] = new Image(); loadings[0].src = "img/game_loading1.png"; loadings[1] = new Image(); loadings[1].src = "img/game_loading2.png"; loadings[2] = new Image(); loadings[2].src = "img/game_loading3.png"; loadings[3] = new Image(); loadings[3].src = "img/game_loading4.png"; var Loading = { img:loadings, width:186, height:38, length:loadings.length }
接下來,新建建構函式來生成圖片,並在loading動畫結束後轉入遊戲執行也就是這裡的RUNNING狀態。
由於定時器時間間隔過快導致loading畫面快速閃過又沒必要重新建立定時器,故這裡用到一個變數來儲存定時器執行次數,可以任意選擇當定時器執行幾次之後切換圖片,這樣更加流暢也更加合理。
// 定義loading圖片的建構函式 function loading(images){ this.img = images.img; this.width = images.width; this.height = images.height; this.length = images.length; this.num = 0; this.times = 0 this.paint = function () { gj.drawImage(this.img[this.num],0,hei-this.height); } this.step = function () { this.times ++ ; //新建一個變數用來儲存定時器作用次數,並用取摸的方式改變定時器作用在此上面的時間間隔。 if (this.times % 6 == 0) { this.num ++ ; } if (this.num == this.length) { state = RUNNING; } } } var wait = new loading(Loading);
4、繪製我方飛機:
首先,我方飛機有不同的狀態,有兩張圖片來實現飛機正常情況下的動態效果,有四張圖片來實現飛機撞毀時的動態效果。所以將這所有的6張圖片儲存在一個數組中方便呼叫。同樣的,也新建一個物件來封裝它的屬性。
// 繪製我方飛機 var hero = []; hero[0] = new Image(); hero[0].src = "img/hero1.png"; hero[1] = new Image(); hero[1].src = "img/hero2.png"; hero[2] = new Image(); hero[2].src = "img/hero_blowup_n1.png"; hero[3] = new Image(); hero[3].src = "img/hero_blowup_n2.png"; hero[4] = new Image(); hero[4].src = "img/hero_blowup_n3.png"; hero[5] = new Image(); hero[5].src = "img/hero_blowup_n4.png"; var Hero = { img : hero, width : 99, height : 124, length : hero.length }
接下來,同樣的,為其建立一個建構函式,獲取之前物件的值,另外定義一些後面會用到的變數,像判斷飛機是否撞毀、定義飛機移動的座標等等,當然,到後面遇到相應功能再新增也是可以的。並且以同樣的方式來呼叫。
而且,我們是用滑鼠來控制飛機的移動,這裡就得有一個onmousemove事件來獲取滑鼠座標並相應改變飛機座標。
function heros (images){ this.img = images.img; this.width = images.width; this.height = images.height; this.length = images.length; this.x = wid/2-this.width/2; this.y = hei-this.height; this.num = 0; this.boom = false; //判斷我方飛機是否發生碰撞, this.paint = function () { gj.drawImage(this.img[this.num],this.x,this.y); } this.step = function () { if (!this.boom) { this.num ++ ; this.num = this.num % 2; //當我方飛機並未發生碰撞,動畫在0 1之間互相轉化形成動畫效果。 }else{ this.num ++ ; if (this.num == this.length) { life -- ; if (life == 0) { this.num = this.length - 1; //當其發生碰撞,畫面停留在碰撞動畫的最後一張,然後進入GAMROVER狀態。 state = GAMEOVER ; } else { heroes = new heros(Hero); } } } } this.booms = function () { this.boom = true; } var times = 0; this.shoot = function (){ times ++ ; if (times % 3 == 0) { bullets.push(new Bullets(Bullet)) //用來向生成的陣列中新增物件元素。 } } } var heroes = new heros(Hero); // 新增滑鼠移動事件,使我方飛機跟隨滑鼠在canvas介面中移動. canvas.onmousemove = function (event) { var event = event || window.event if (state == RUNNING) { var x = event.offsetX; var y = event.offsetY; heroes.x = x - heroes.width/2; heroes.y = y - heroes.width/2; } }
5、繪製子彈並理清子彈的執行邏輯:
首先如同之前一樣,繪出子彈的圖片,注意子彈是從飛機頭射出,注意調整座標定位。
// 繪製我方飛機的子彈, var bullet = new Image (); bullet.src = "img/bullet1.png"; var Bullet = { img : bullet, width : 9, height : 21 } function Bullets(images){ this.img = images.img; this.width = images.width; this.height = images.height; this.x = heroes.x + heroes.width/2 - this.width/2; this.y = heroes.y - this.height - 10; this.boom = false; this.paint = function () { gj.drawImage(this.img,this.x,this.y); } this.step = function () { this.y -= 10; } this.booms = function () { this.boom = true; } }
這裡我們需要了解到的是,每一顆生成的子彈都是一個獨立的物件,所以不能像之前那樣呼叫函式。
這裡我們新建一個數組用來儲存每一個生成的子彈物件,迴圈遍歷所有生成的子彈使其全都擁有同樣且獨立的產生方法和運動形式。
並且每一顆子彈撞到敵方飛機或者飛出canvas介面之外,我們將其從陣列中清除,使其執行更為流暢。
// 每一顆子彈都是一個獨立的物件,這裡新建一個數組用來儲存所有的子彈. var bullets = []; function bulletsPaint(){ for (var i = 0;i < bullets.length;i++) { bullets[i].paint(); } } function bulletsStep(){ for (var i = 0;i < bullets.length;i++) { bullets[i].step(); } } function bulletsDel(){ for (var i = 0;i < bullets.length;i++) { if (bullets[i].boom || bullets[i].y < -bullets[i].height) { bullets.splice(i,1); } } }
這次我們先做到這裡,下次做完一個完整的飛機大戰遊戲。