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); } } }

這次我們先做到這里,下次做完一個完整的飛機大戰游戲。
