最開始咱們要初始化信息,咱們有五個狀態:遊戲封面,加載狀態,運行狀態,遊戲暫停,遊戲結束。javascript
咱們還須要 得分--score,生命--life。css
var START = 1;//初始狀態 var LOADING = 2;//加載狀態 var RUNNING = 3;//遊戲運行狀態 var WAIT = 4;//遊戲暫停狀態 var GAMEOVER = 5;//遊戲結束狀態 var state = START;//初始狀態 var score = 0;//遊戲得分 var life = 5;//我方飛機的生命值
1.遊戲開始界面html
咱們建立一個背景的構造函數,爲了製造背景的動態效果,咱們建立兩張背景java
第一張圖片的位置爲(0,0)canvas
第二張圖片咱們放在第一張圖片的上面,數組
當第一張圖片運動到最底下時,而後把第一張圖片放在第二張圖片的上面dom
當第二張圖片運動到最底下時,而後把第二張圖片放在第一張圖片的上面函數
var bg = new Image();//建立一個圖片對象 bg.src = "img/background.png"; var BG = { imgs:bg, width:480, height:850 } //建立一個背景的構造函數 //爲了製造背景的動態效果,咱們建立兩張背景 function Bg(config){ this.imgs = config.imgs; this.width = config.width; this.height = config.height; this.x1 = 0; this.y1 = 0; this.x2 = 0; this.y2 = -this.height; //繪製圖片的方法 this.paint = function(){ ctx.drawImage(this.imgs,this.x1,this.y1); ctx.drawImage(this.imgs,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 sky = new Bg(BG); //建立logo var logo = new Image(); logo.src = "img/start.png";
效果以下:動畫
2.遊戲加載界面this
首先咱們定義一個數組存儲圖片,數組裏的每位元素都建立一個image對象,緣由是怕canvas加載太快,圖片資源沒有獲取到,致使畫布上面沒有東西
經過數組的索引值的改變來讓圖片好像運動起來;
還要給畫布加一個點擊事件,必須是開始的狀態才能跳轉到遊戲加載狀態
//2.遊戲加載界面 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 LOADINGS = { imgs:loadings, length:loadings.length, width:186, height:38 } //加載運動圖片的構造函數 function Loading(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; this.startindex = 0;//定義一個訪問數組中圖片的索引 this.x1 = 0; this.y1 = HEIGHT - this.height; this.time = 0; this.paint = function(){ ctx.drawImage(this.imgs[this.startindex],this.x1,this.y1) } this.step = function(){ this.time++;//由於定時器設置的時間過短了,因此定義了一個時間來進行緩衝 if (this.time%3==0) { this.startindex++; } if (this.startindex == this.length) { state = RUNNING;//當全部圖片展現完成,進入下一個狀態 } } } //運動圖片對象 var loading = new Loading(LOADINGS); //給畫布添加點擊事件 ocanvas.onclick = function(){ if (state == START) { state = LOADING; } }
效果圖以下:
3.我方飛機
依舊建立一個數組來存儲圖片,建立一個我方飛機的構造函數
Hero構造函數多出了幾個屬性,判斷是否被撞擊和是否被撞擊完畢
我方飛機會隨着鼠標運動,因此給畫布添加一個鼠標移動的事件,爲了使鼠標在我方飛機圖片的正中央,還須要減去我方飛機圖片的寬高各一半
其射擊函數其實就是生成多個子彈對象
//3.我方飛機 var heros = []; heros[0] = new Image(); heros[0].src = "img/hero1.png"; heros[1] = new Image(); heros[1].src = "img/hero2.png"; heros[2] = new Image(); heros[2].src = "img/hero_blowup_n1.png"; heros[3] = new Image(); heros[3].src = "img/hero_blowup_n2.png"; heros[4] = new Image(); heros[4].src = "img/hero_blowup_n3.png"; heros[5] = new Image(); heros[5].src = "img/hero_blowup_n4.png"; var HEROS = { imgs:heros, length:heros.length, width:99, height:124 } function Hero(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; this.startindex = 0; this.x1 = WIDTH/2 - this.height/2; this.y1 = HEIGHT - 150; this.down = false;//是否被撞擊 this.time = 0; this.bang = function(){ this.down = true; } this.paint = function(){ ctx.drawImage(this.imgs[this.startindex],this.x1,this.y1); } this.step = function(){ if (!this.down) {// if (this.startindex == 0) { this.startindex = 1; } else{ this.startindex = 0; } } else{ this.startindex++; if (this.startindex == this.length) { life--; if (life <= 0) { state = GAMEOVER; this.startindex = this.length - 1; }else{ hero = new Hero(HEROS); } } } } this.shoot = function(){//就是生成多個子彈對象 this.time++; if (this.time%3==0) { bullet.push(new Bullet(BULLETS)); } } } var hero = new Hero(HEROS); ocanvas.onmousemove = function(event){ var event = event||window.event; var x = event.offsetX; var y = event.offsetY; if (state == RUNNING) { hero.x1 = x - hero.width/2; hero.y1 = y - hero.height/2; } }
效果圖以下:
3.子彈
子彈從新定義一個對象,而後在我方飛機定義一個射擊函數,用來生成子彈的對象。
若是子彈對象撞擊到別的東西或者運動出畫布會自動消失,子彈對象經過遍歷調用自身顯示,運動功能。
直接在全局定義函數,遍歷調用子彈本身自己。
//4.我方子彈 var bullets = []; bullets[0] = new Image(); bullets[0].src = "img/bullet1.png"; var BULLETS = { imgs:bullets, length:bullets.length, width:9, height:21 } function Bullet(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; this.x1 = hero.x1 + hero.width/2 - this.width/2; this.y1 = hero.y1 - this.height-10; this.startindex = 0; this.down = false; this.paint = function(){ ctx.drawImage(this.imgs[this.startindex],this.x1,this.y1); } this.step = function(){ this.y1-=10; } this.bang = function(){ this.down = true; } } var bullet = []; function bulletPaint(){ for (var i=0;i<bullet.length;i++) { bullet[i].paint(); } } function bulletStep(){ for (var i=0;i<bullet.length;i++) { bullet[i].step(); } } function bulletDown(){ for (var i=0;i<bullet.length;i++) { if (bullet[i].down == true||bullet[i].y1<-bullet[i].height) { bullet.splice(i,1); } } }
4.敵方飛機(重難點)
首先敵方飛機的種類就有三種,因此敵方飛機對象要多加一個type屬性,這樣才能區別對待
而後大飛機還有動畫,因此又加了一個frame屬性,
比較重要的大概就是碰撞檢測和碰撞以後的處理,
碰撞檢測:
有參數,由於咱們有多是我放飛機和敵方飛機相撞,有多是子彈與地方飛機相撞
function Enemy(config){ this.imgs = config.imgs, this.length = config.length; this.width = config.width; this.height = config.height; this.type = config.type; this.life = config.life; this.score = config.score; this.frame = config.frame; this.startindex = 0; this.x1 = Math.random()*(WIDTH-this.width); this.y1 = -this.height; this.down = false;//是否被撞擊 this.cancel = false;//肯定當前動畫是否播放完 this.paint = function(){ ctx.drawImage(this.imgs[this.startindex],this.x1,this.y1); } this.step = function(){ if (!this.down) { this.startindex++; this.startindex = this.startindex % this.frame; this.y1+=10; if (this.y1+this.height>HEIGHT) {//當敵方飛機到達畫布底部,尚未被擊敗,遊戲將停止 state = GAMEOVER; } } else{ this.startindex++; if (this.startindex == this.length) { this.cancel = true; this.startindex = this.length - 1; } } } this.bang = function(){ this.life--;//當前飛機的生命值減小 if (this.life == 0) { this.down = true; score += this.score; } } this.checkHit = function(obj){ return this.x1<obj.x1+obj.width&&this.x1+this.width>obj.x1&&this.y1<obj.y1+obj.height&&this.y1+this.height>obj.y1; } } var enemies = [];
碰撞函數:
敵方飛機和子彈碰撞時,子彈會有一個循環,看看你撞的是頁面中哪個子彈
function checkHitBoth(){//碰撞處理函數 for (var i= 0;i<enemies.length;i++) { //hero和敵方飛機碰撞 if(enemies[i].checkHit(hero)){//調用敵方飛機的碰撞檢測函數 enemies[i].bang(); hero.bang(); } //子彈和敵方飛機碰撞 for(var j = 0;j<bullet.length;j++){ if(enemies[i].checkHit(bullet[j])){//調用敵方飛機的碰撞檢測函數 enemies[i].bang(); bullet[j].bang(); } } } }
敵方飛機的建立:
function enemiesCreate(){ var ran = Math.floor(Math.random()*100); if (ran<=5) { enemies.push(new Enemy(ENEMY1)); }else if (ran == 6) { enemies.push(new Enemy(ENEMY2)); }else if (ran == 7) { if (enemies[0]) {//判斷敵方飛機數組是否有東西 if (enemies[0].type!=3) {//爲了保證畫布裏只顯示一張大飛機,判斷敵方飛機數組的第0位是不是大飛機 enemies.splice(0,0,new Enemy(ENEMY3));//插在數組的最前面,是的數組的第一位是大飛機 } } } }
效果圖以下:
5.遊戲暫停
當鼠標移出畫布時,和當前遊戲狀態處於運行狀態,遊戲狀態才能轉換到暫停狀態
當鼠標移入畫布時,當前遊戲狀態處於暫停狀態,遊戲狀態才能轉換到遊戲運行狀態
var pause = new Image(); pause.src = "img/game_pause_nor.png"; ocanvas.onmouseover = function(){ if (state == WAIT) { state = RUNNING; } } ocanvas.onmouseout = function(){ if (state == RUNNING) { state = WAIT; } }
完整代碼:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <style type="text/css"> div{ margin: 0 auto; text-align: center; } </style> </head> <body> <div> <canvas id="" width="480" height="650"></canvas> </div> <script type="text/javascript"> var ocanvas = document.getElementsByTagName("canvas")[0]; var ctx = ocanvas.getContext("2d"); var START = 1;//初始狀態 var LOADING = 2;//加載狀態 var RUNNING = 3;//遊戲運行狀態 var WAIT = 4;//遊戲暫停狀態 var GAMEOVER = 5;//遊戲結束狀態 var WIDTH = 480; var HEIGHT = 650; var state = START;//初始狀態 var score = 0;//遊戲得分 var life = 5;//我方飛機的生命值 //1.遊戲開始界面 var bg = new Image();//建立一個圖片對象 bg.src = "img/background.png"; var BG = { imgs:bg, width:480, height:850 } //建立一個背景的構造函數 //爲了製造背景的動態效果,咱們建立兩張背景 function Bg(config){ this.imgs = config.imgs; this.width = config.width; this.height = config.height; this.x1 = 0; this.y1 = 0; this.x2 = 0; this.y2 = -this.height; //繪製圖片的方法 this.paint = function(){ ctx.drawImage(this.imgs,this.x1,this.y1); ctx.drawImage(this.imgs,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 sky = new Bg(BG); //建立logo var logo = new Image(); logo.src = "img/start.png"; //2.遊戲加載界面 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 LOADINGS = { imgs:loadings, length:loadings.length, width:186, height:38 } //加載運動圖片的構造函數 function Loading(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; this.startindex = 0;//定義一個訪問數組中圖片的索引 this.x1 = 0; this.y1 = HEIGHT - this.height; this.time = 0; this.paint = function(){ ctx.drawImage(this.imgs[this.startindex],this.x1,this.y1) } this.step = function(){ this.time++;//由於定時器設置的時間過短了,因此定義了一個時間來進行緩衝 if (this.time%3==0) { this.startindex++; } if (this.startindex == this.length) { state = RUNNING;//當全部圖片展現完成,進入下一個狀態 } } } //運動圖片對象 var loading = new Loading(LOADINGS); //給畫布添加點擊事件 ocanvas.onclick = function(){ if (state == START) { state = LOADING; } } //3.我方飛機 var heros = []; heros[0] = new Image(); heros[0].src = "img/hero1.png"; heros[1] = new Image(); heros[1].src = "img/hero2.png"; heros[2] = new Image(); heros[2].src = "img/hero_blowup_n1.png"; heros[3] = new Image(); heros[3].src = "img/hero_blowup_n2.png"; heros[4] = new Image(); heros[4].src = "img/hero_blowup_n3.png"; heros[5] = new Image(); heros[5].src = "img/hero_blowup_n4.png"; var HEROS = { imgs:heros, length:heros.length, width:99, height:124 } function Hero(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; this.startindex = 0; this.x1 = WIDTH/2 - this.height/2; this.y1 = HEIGHT - 150; this.down = false;//是否被撞擊 this.time = 0; this.bang = function(){ this.down = true; } this.paint = function(){ ctx.drawImage(this.imgs[this.startindex],this.x1,this.y1); } this.step = function(){ if (!this.down) {//判斷是否撞擊 if (this.startindex == 0) { this.startindex = 1; } else{ this.startindex = 0; } } else{//被撞了 this.startindex++; if (this.startindex == this.length) { life--;//生命值減一 if (life <= 0) {//當生命值小於等於0時 state = GAMEOVER; this.startindex = this.length - 1;//定格在最後一刻 }else{ hero = new Hero(HEROS);//若是生命值不爲0, } } } } this.shoot = function(){//就是生成多個子彈對象 this.time++; if (this.time%3==0) { bullet.push(new Bullet(BULLETS)); } } } var hero = new Hero(HEROS); ocanvas.onmousemove = function(event){ var event = event||window.event; var x = event.offsetX; var y = event.offsetY; if (state == RUNNING) { hero.x1 = x - hero.width/2; hero.y1 = y - hero.height/2; } } //4.我方子彈 var bullets = []; bullets[0] = new Image(); bullets[0].src = "img/bullet1.png"; var BULLETS = { imgs:bullets, length:bullets.length, width:9, height:21 } function Bullet(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; this.x1 = hero.x1 + hero.width/2 - this.width/2; this.y1 = hero.y1 - this.height-10; this.startindex = 0; this.down = false; this.paint = function(){ ctx.drawImage(this.imgs[this.startindex],this.x1,this.y1); } this.step = function(){ this.y1-=10; } this.bang = function(){ this.down = true; } } var bullet = []; function bulletPaint(){ for (var i=0;i<bullet.length;i++) { bullet[i].paint(); } } function bulletStep(){ for (var i=0;i<bullet.length;i++) { bullet[i].step(); } } function bulletDown(){ for (var i=0;i<bullet.length;i++) { if (bullet[i].down == true||bullet[i].y1<-bullet[i].height) { bullet.splice(i,1); } } } var enemy1 = [];//小飛機 enemy1[0] = new Image(); enemy1[0].src = "img/enemy1.png"; enemy1[1] = new Image(); enemy1[1].src = "img/enemy1_down1.png"; enemy1[2] = new Image(); enemy1[2].src = "img/enemy1_down2.png"; enemy1[3] = new Image(); enemy1[3].src = "img/enemy1_down3.png"; enemy1[4] = new Image(); enemy1[4].src = "img/enemy1_down4.png"; var enemy2 = [];//中飛機 enemy2[0] = new Image(); enemy2[0].src = "img/enemy2.png"; enemy2[1] = new Image(); enemy2[1].src = "img/enemy2_down1.png"; enemy2[2] = new Image(); enemy2[2].src = "img/enemy2_down2.png"; enemy2[3] = new Image(); enemy2[3].src = "img/enemy2_down3.png"; enemy2[4] = new Image(); enemy2[4].src = "img/enemy2_down4.png"; var enemy3 = [];//大飛機 enemy3[0] = new Image(); enemy3[0].src = "img/enemy3_n1.png"; enemy3[1] = new Image(); enemy3[1].src = "img/enemy3_n2.png"; enemy3[2] = new Image(); enemy3[2].src = "img/enemy3_down1.png"; enemy3[3] = new Image(); enemy3[3].src = "img/enemy3_down2.png"; enemy3[4] = new Image(); enemy3[4].src = "img/enemy3_down3.png"; enemy3[5] = new Image(); enemy3[5].src = "img/enemy3_down4.png"; enemy3[6] = new Image(); enemy3[6].src = "img/enemy3_down5.png"; enemy3[7] = new Image(); enemy3[7].src = "img/enemy3_down6.png"; var ENEMY1 = { imgs : enemy1, length : enemy1.length, width : 57, height : 51, type : 1, life : 1, score : 1, frame : 1 } var ENEMY2 = { imgs : enemy2, length : enemy2.length, width : 69, height : 95, type : 2, life : 3, score : 3, frame : 1 } var ENEMY3 = { imgs : enemy3, length : enemy3.length, width : 165, height : 261, type : 3, life : 10, score : 10, frame : 2 } function Enemy(config){ this.imgs = config.imgs, this.length = config.length; this.width = config.width; this.height = config.height; this.type = config.type; this.life = config.life; this.score = config.score; this.frame = config.frame; this.startindex = 0; this.x1 = Math.random()*(WIDTH-this.width); this.y1 = -this.height; this.down = false;//是否被撞擊 this.cancel = false;//肯定當前動畫是否播放完 this.paint = function(){ ctx.drawImage(this.imgs[this.startindex],this.x1,this.y1); } this.step = function(){ if (!this.down) { this.startindex++; this.startindex = this.startindex % this.frame; this.y1+=10; if (this.y1+this.height>HEIGHT) {//當敵方飛機到達畫布底部,尚未被擊敗,遊戲將停止 state = GAMEOVER; } } else{ this.startindex++; if (this.startindex == this.length) { this.cancel = true; this.startindex = this.length - 1; } } } this.bang = function(){ this.life--;//當前飛機的生命值減小 if (this.life == 0) { this.down = true; score += this.score; } } this.checkHit = function(obj){ return this.x1<obj.x1+obj.width&&this.x1+this.width>obj.x1&&this.y1<obj.y1+obj.height&&this.y1+this.height>obj.y1; } } var enemies = []; function enemiesCreate(){ var ran = Math.floor(Math.random()*100); if (ran<=5) { enemies.push(new Enemy(ENEMY1)); }else if (ran == 6) { enemies.push(new Enemy(ENEMY2)); }else if (ran == 7) { if (enemies[0]) {//判斷敵方飛機數組是否有東西 if (enemies[0].type!=3) {//爲了保證畫布裏只顯示一張大飛機,判斷敵方飛機數組的第0位是不是大飛機 enemies.splice(0,0,new Enemy(ENEMY3));//插在數組的最前面,是的數組的第一位是大飛機 } } } } function enemiesPaint(){ for (var i = 0;i<enemies.length;i++) { enemies[i].paint(); } } function enemiesStep(){ for (var i = 0;i<enemies.length;i++) { enemies[i].step(); } } function enemiesDel(){ for (var i = 0;i<enemies.length;i++) { if (enemies[i].cancel||enemies[i].y1>HEIGHT) { enemies.splice(i,1);//刪除當前元素 } } } function checkHitBoth(){//碰撞處理函數 for (var i= 0;i<enemies.length;i++) { //hero和敵方飛機碰撞 if(enemies[i].checkHit(hero)){//調用敵方飛機的碰撞檢測函數 enemies[i].bang(); hero.bang(); } //子彈和敵方飛機碰撞 for(var j = 0;j<bullet.length;j++){ if(enemies[i].checkHit(bullet[j])){//調用敵方飛機的碰撞檢測函數 enemies[i].bang(); bullet[j].bang(); } } } } var pause = new Image(); pause.src = "img/game_pause_nor.png"; ocanvas.onmouseover = function(){ if (state == WAIT) { state = RUNNING; } } ocanvas.onmouseout = function(){ if (state == RUNNING) { state = WAIT; } } function paintText(){ ctx.font = "bold 24px 微軟雅黑"; ctx.fillText("SCORE:"+score,20,30); ctx.fillText("LIFE:"+life,380,30); } function paintGameover(){ ctx.font = "bold 36px 微軟雅黑"; ctx.fillText("GAMEOVER",150,300); } setInterval(function(){ sky.paint(); sky.step(); if (state == START) {//當遊戲狀態爲開始狀態時 ctx.drawImage(logo,40,0); }else if (state == LOADING) { loading.paint(); loading.step(); }else if (state == RUNNING) { hero.paint();//我方飛機繪製 hero.step();//我方飛機運動 hero.shoot();//我方飛機射擊子彈 bulletPaint();//遍歷子彈,讓全部子彈顯示 bulletStep();//遍歷子彈,讓子彈運動 bulletDown();//遍歷子彈,擊中飛機的子彈或者畫布外的子彈本身銷燬 enemiesCreate()//建立敵方飛機 enemiesPaint();//遍歷敵方飛機數組讓敵方飛機顯示 enemiesStep();//遍歷敵方飛機讓全部飛機運動 enemiesDel();//銷燬符合條件的敵方飛機 checkHitBoth(); paintText();//繪製得分和生命值 }else if (state == WAIT) {//保存當前運動狀態 hero.paint(); bulletPaint(); enemiesPaint(); ctx.drawImage(pause,200,300); paintText(); }else if (state == GAMEOVER) { paintText(); paintGameover(); } },100) </script> </body> </html>