效果图
1.欢迎界面 背景图一直在动
2.游戏阶段
3.结束
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> canvas{ display: block; margin: 0 auto; /* border: 1px solid #000; */ } </style> </head> <body> <canvas id="canvas" width="480" height="650"></canvas> <script> var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); //初始化阶段 //将游戏分几个阶段 const START = 0; //第一阶段 游戏欢迎阶段 const STARTING = 1; //第二阶段 游戏加载阶段 const RUNNING = 2; //第三阶段 游戏运行阶段 const PAUSE = 3; //第四阶段 游戏暂停阶段 const GAMEOVER = 4; //第五阶段 游戏结束阶段 //定义一个自己的状态和上面的状态作比较 var state = START; //定义画布的宽和高 var WIDTH = 480; var HEIGHT = 650; //定义游戏的分数 var score = 0; //定义我方飞机的生命值 var life = 3; //初始化阶段结束 //第一阶段 游戏欢迎阶段 //加载背景图片 var bg = new Image(); bg.src = "images/background.png"; //初始化背景图片的数据 var BG = { imgs : bg, width : 480, height : 852 } //定义构造函数 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(){ context.drawImage(this.imgs,this.x1,this.y1) context.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 abc = new Bg(BG); //加载LOGO var logo = new Image(); logo.src = "images/start.png"; //第二阶段 //创建图片的构造 var loadings = []; loadings[0] = new Image(); loadings[0].src = "images/game_loading1.png" loadings[1] = new Image(); loadings[1].src = "images/game_loading2.png" loadings[2] = new Image(); loadings[2].src = "images/game_loading3.png" loadings[3] = new Image(); loadings[3].src = "images/game_loading4.png" //初始化图片数据 var LOADING = { imgs:loadings, length:loadings.length, width:186, height:38 } //写构造函数 function Loadings(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; //定义索引 this.startIndex = 0; //定义绘制方法 this.paint = function(){ context.drawImage(this.imgs[this.startIndex],0,HEIGHT-this.height) } //定义一个速度 this.time = 0; //定义运动方法 this.step = function(){ this.time++; if(this.time%4 == 0){ this.startIndex++; } if(this.startIndex == this.length){ state = RUNNING; } } } //创建游戏加载的对象 var loading = new Loadings(LOADING); //鼠标点击事件 canvas.onclick = function(){ if(state == START){ state = STARTING; } } //第三阶段 //加载我方飞机图片 var heros = []; heros[0] = new Image(); heros[0].src = "images/hero1.png"; heros[1] = new Image(); heros[1].src = "images/hero2.png"; heros[2] = new Image(); heros[2].src = "images/hero_blowup_n1.png"; heros[3] = new Image(); heros[3].src = "images/hero_blowup_n2.png"; heros[4] = new Image(); heros[4].src = "images/hero_blowup_n3.png"; heros[5] = new Image(); heros[5].src = "images/hero_blowup_n4.png"; //初始化飞机数据 var HEROS = { imgs : heros, length : heros.length, width : 99, height : 124, frame : 2 //添加一个状态 } //我方飞机的构造函数 function Hero(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; this.frame = config.frame; //定义索引 this.startIndex = 0; //我方飞机位置 this.x = WIDTH/2 - this.width/2; this.y = HEIGHT - 150; //定义飞机撞击状态 this.down = false; //定义飞机爆炸状态 this.candel = false; //绘制方法 this.paint = function(){ context.drawImage(this.imgs[this.startIndex],this.x,this.y); } //运动方法 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 -- ;//我方飞机爆炸完后,生命值减一 //判断生命值为0时,游戏结束 if(life == 0){ state = GAMEOVER; //虽然游戏结束了但是还停留在最后一张图的状态 this.startIndex = this.length - 1; //想要开始新的生命时,直接给出创建的新的对象 }else{ hero = new Hero(HEROS); } } } } //定义射击速度初始值为0 this.time = 0; //射击方法 this.shoot = function(){ this.time ++; if(this.time % 3 == 0){ bullets.push(new Bullet(BULLET)); } } // 定义我方飞机碰撞的方法 this.bang = function(){ this.down = true; } } //创建我方飞机 var hero = new Hero(HEROS); // 飞机跟随鼠标移动 canvas.onmousemove = function(event){ if(state == RUNNING){//判断当前游戏状态 var x = event.offsetX; var y = event.offsetY; // 直接赋值给飞机的x和y坐标 hero.x = x - hero.width/2; hero.y = y - hero.height/2; } } //绘制子弹 //加载子弹的图片 var bullet = new Image(); bullet.src = "images/bullet1.png"; //初始化子弹数据 var BULLET = { imgs : bullet, width : 9, height : 21 } //子弹的构造函数 function Bullet(config){ this.imgs = config.imgs; this.width = config.width; this.height = config.height; // 子弹的坐标 this.x = hero.x + hero.width/2 - this.width/2; this.y = hero.y - this.height; // 定义绘制方法 this.paint = function(){ context.drawImage(this.imgs,this.x,this.y); } // 定义运动方法 this.step = function(){ this.y -= 10; } // 加上一个标识,标识子弹是否发生碰撞 this.candel = false; // 撞击的方法,用于修改子弹是否碰撞的属性 this.bang = function(){ this.candel = true; } } //增加一个数组用来存储子弹 var bullets = [] //绘制数组里所有的子弹 function bulletsPaint(){ for(var i = 0;i < bullets.length;i++){ //调用数组对象中的方法paint() 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].y < -bullets[i].height || bullets[i].candel){ bullets.splice(i,1); } } } //绘制我方飞机 //加载图片 //小飞机 var enemy1 = []; enemy1[0] = new Image(); enemy1[0].src = "images/enemy1.png"; enemy1[1] = new Image(); enemy1[1].src = "images/enemy1_down1.png"; enemy1[2] = new Image(); enemy1[2].src = "images/enemy1_down2.png"; enemy1[3] = new Image(); enemy1[3].src = "images/enemy1_down3.png"; enemy1[4] = new Image(); enemy1[4].src = "images/enemy1_down4.png"; // 中飞机 var enemy2 = []; enemy2[0] = new Image(); enemy2[0].src = "images/enemy2.png"; enemy2[1] = new Image(); enemy2[1].src = "images/enemy2_down1.png"; enemy2[2] = new Image(); enemy2[2].src = "images/enemy2_down2.png"; enemy2[3] = new Image(); enemy2[3].src = "images/enemy2_down3.png"; enemy2[4] = new Image(); enemy2[4].src = "images/enemy2_down4.png"; // 大飞机 var enemy3 = []; enemy3[0] = new Image(); enemy3[0].src = "images/enemy3_n1.png"; enemy3[1] = new Image(); enemy3[1].src = "images/enemy3_n2.png"; enemy3[2] = new Image(); enemy3[2].src = "images/enemy3_down1.png"; enemy3[3] = new Image(); enemy3[3].src = "images/enemy3_down2.png"; enemy3[4] = new Image(); enemy3[4].src = "images/enemy3_down3.png"; enemy3[5] = new Image(); enemy3[5].src = "images/enemy3_down4.png"; enemy3[6] = new Image(); enemy3[6].src = "images/enemy3_down5.png"; enemy3[7] = new Image(); enemy3[7].src = "images/enemy3_down6.png"; //初始化敌方飞机的数据 var ENEMY1 = { imgs : enemy1, length : enemy1.length, width : 57, height : 51, type : 1, //增加一个类型,判断是哪一种飞机 frame : 1, life : 1, score : 1 } var ENEMY2 = { imgs : enemy2, length : enemy2.length, width : 69, height : 95, type : 2, //增加一个类型,判断是哪一种飞机 frame : 1, life : 5, score : 5 } var ENEMY3 = { imgs : enemy3, length : enemy3.length, width : 165, height : 261, type : 3, //增加一个类型,判断是哪一种飞机 frame : 2, life : 15, score : 20 } //敌方飞机的构造函数 function Enemy(config){ this.imgs = config.imgs; this.length = config.length; this.width = config.width; this.height = config.height; this.type = config.type; this.frame = config.frame; this.life = config.life; this.score = config.score; //定义敌方飞机的坐标 this.x = Math.random() * (WIDTH - this.width); this.y = -this.height; //定义索引 this.startIndex = 0; //定义一个标识 //没有碰撞为false this.down = false; //定义是否爆炸完成的属性 this.candel = false; //定义绘制方法 this.paint = function(){ context.drawImage(this.imgs[this.startIndex],this.x,this.y); } //定义运动方法 this.step = function(){ if(!this.down){//飞机处于正常状态 //小飞机,中飞机的下标始终都是0 //大飞机的下标是在0和1之间进行切换 this.startIndex ++; this.startIndex = this.startIndex % this.frame; this.y ++; }else{ this.startIndex++; if(this.startIndex == this.length){ this.candel = true; this.startIndex = this.length - 1; } } } //是否被碰撞的方法 this.checkHit = function(zd){ return zd.y + zd.height > this.y && zd.x + zd.width > this.x && zd.y < this.y + this.height && zd.x < this.x + this.width } //敌方飞机碰撞以后的方法 this.bang = function(){ this.life -- ; if(this.life == 0){ this.down = true; score += this.score; } } } // 创建数组,用于存储敌方飞机 var enemies = []; // 数组中去添加飞机 function pushEnemies(){ //定义一个变量存放随机数 var numRand = Math.floor(Math.random() * 100); if(numRand < 10){ //添加小飞机 enemies.push(new Enemy(ENEMY1)) }else if(numRand > 98){ //添加中飞机 enemies.push(new Enemy(ENEMY2)) }else if(numRand == 50){ //添加大飞机 enemies.push(new Enemy(ENEMY3)) } } // 敌方飞机的绘制函数 function paintEnemies(){ for(var i = 0;i < enemies.length;i++){ enemies[i].paint() } } // 敌方飞机的运动函数 function stepEnemies(){ for(var i = 0;i < enemies.length;i++){ enemies[i].step() } } // 敌方飞机的删除函数 function delEnemies(){ for(var i = 0;i < enemies.length;i++){ // 两种情况 if(enemies[i].y > HEIGHT || enemies[i].candel){ enemies.splice(i,1); } } } // 检测是否撞击 function hitEnemies(){ for(var i = 0;i < enemies.length;i++){ // 如果我方飞机撞到了敌方飞机以后 if(enemies[i].checkHit(hero)){ // 处理敌方飞机碰撞以后的逻辑 enemies[i].bang(); // 处理我方飞机碰撞以后的逻辑 hero.bang(); } // 子弹如果碰到敌方飞机以后 for(var j = 0;j < bullets.length;j++){ if(enemies[i].checkHit(bullets[j])){ enemies[i].bang(); bullets[j].bang(); } } } } // 文本函数 绘制分数和生命值 function paintText(){ context.font = "bold 30px 微软雅黑"; context.fillText("SCORE:" + score,10,30); context.fillText("LIFE:" + life,300,30); } // 第四阶段 游戏暂停 canvas.onmouseout = function(){ if(state == RUNNING){ state = PAUSE; } } canvas.onmouseover = function(){ if(state == PAUSE){ state = RUNNING; } } var pause = new Image(); pause.src = "images/game_pause_nor.png"; // 第五阶段 游戏GG function paintOver(){ context.font = "bold 50px 微软雅黑"; context.fillText("GAME OVER!!!",50,250); } setInterval(function(){ abc.paint() abc.step() switch(state){ case START: context.drawImage(logo,40,0); break; case STARTING: loading.paint(); loading.step(); break; case RUNNING: hero.paint(); hero.step(); hero.shoot(); bulletsPaint(); bulletsStep(); bulletsDel(); pushEnemies(); paintEnemies(); stepEnemies(); delEnemies(); hitEnemies(); paintText(); break; case PAUSE: hero.paint(); bulletsPaint(); paintEnemies(); paintText(); context.drawImage(pause,150,350); break; case GAMEOVER: hero.paint(); bulletsPaint(); paintEnemies(); paintText(); paintOver() break; } },10) </script> </body> </html>