用Js实现一个好玩的飞机大战,简单!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
canvas{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="canvas" width="512" height="768"></canvas>
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
// 0 游戏初始化的一些数据
// 0.1 把上面游戏的五个阶段整理成数字
const START = 0;
const STARTTING = 1;
const RUNNING = 2;
const PAUSE = 3;
const GAMEOVER = 4;
// 0.2 定义一个自己的状态,时刻跟上面的五个状态进行比较,然后判断游戏目前处于哪个阶段
var state = START;
// 0.3 画布的信息得获取过来
const WIDTH = 512;
const HEIGHT = 768;
// 0.4 游戏的分数
var score = 0;
// 0.5 我方飞机的生命
var life = 3;
// 1 第一阶段 游戏欢迎阶段
// 1.1 加载背景图片
// 1.1.1 创建背景图片的dom对象
var bg = new Image();
bg.src = "img/1.jpg";
// 1.1.2 背景图片的详细信息(用对象表示)
var BG = {
imgs : bg,
width : 512,
height : 768
}
// 1.1.3 自定义构造函数,构造背景图片的
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;
}
}
}
// 1.1.4 创建背景图片的对象
var abc = new Bg(BG)
// 1.2 加载LOGO
var logo = new Image();
logo.src = "img/start.png";
// 2 第二阶段 游戏过渡阶段
// 2.1 创建图片的构造
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"
// 2.2 图片的详细信息
var LOADINGS = {
imgs : loadings,
length : loadings.length,
width : 186,
height : 38
}
// 2.3 动画效果的构造
function Loading(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 % 5 == 0){
this.startIndex ++;
}
// 临界点,图片加载完成以后,到第三阶段去
if(this.startIndex == this.length){
state = RUNNING;
}
}
}
// 2.4 动画效果的对象
var loading = new Loading(LOADINGS);
// 2.5 onclick
canvas.onclick = function(){
if(state == START){
state = STARTTING;
}
}
// 3 第三阶段 游戏运行中
// 3.1 绘制我方飞机
// 3.1.1 加载我方飞机的图片(1.飞机正常运行的状态,2.飞机碰撞以后的状态)
var heros = [];
heros[0] = new Image();
heros[0].src = "img/myhero.png";
heros[1] = new Image();
heros[1].src = "img/myhero.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";
// 3.1.2 初始化我方飞机的数据
var HEROS = {
imgs : heros,
length : heros.length,
width : 135,
height : 131,
frame : 2 //添加一个状态
}
// 3.1.3 我方飞机的构造函数
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 - 100;
// 增加一个标识,表示飞机是否发生了碰撞,给个false,表示一直没有碰撞
this.down = false;
// 增加一个标识,表示飞机碰撞以后,碰撞的动画,碰撞的动画是否执行完成
this.candel = false;
// 绘制方法
this.paint = function(){
context.drawImage(this.imgs[this.startIndex],this.x,this.y);
}
// 运动方法
this.step = function(){
// 监测飞机是否碰撞的属性,如果没有碰撞,索引在0和1之间切换
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.time = 0;
//射击方法
this.shoot = function(){
this.time ++;
if(this.time % 4 == 0){
bullets.push(new Bullet(BULLET));
}
}
this.bang = function(){
this.down = true;
}
}
// 3.1.4 创建对象
var hero = new Hero(HEROS);
// 3.1.5 飞机跟随鼠标移动
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;
}
}
// 3.2 绘制子弹
// 3.2.1 加载子弹的图片
var bullet = new Image();
bullet.src = "img/2.png";
// 3.2.2 初始化子弹的数据
var BULLET = {
imgs : bullet,
width : 19,
height : 29
}
// 3.2.3 子弹的构造函数
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;
}
}
// 3.2.4 增加一个数组,用来存储子弹
var bullets = [];
// 3.2.5 绘制数组里面的所有的子弹
function bulletsPaint(){
for(var i = 0;i < bullets.length;i++){
bullets[i].paint()
}
}
// 3.2.6 绘制数组里面的所有的子弹的运动
function bulletsStep(){
for(var i = 0;i < bullets.length;i++){
bullets[i].step()
}
}
// 3.2.7 当子弹移出画布的时候和发生碰撞以后,要把子弹从数组中删除
function bulletsDel(){
for(var i = 0;i < bullets.length;i++){
if(bullets[i].y < -bullets[i].height || bullets[i].candel){
bullets.splice(i,1);
}
}
}
// 3.3 绘制地方飞机
// 3.3.1 加载敌方飞机的图片(3种)
// 小飞机
var enemy1 = [];
enemy1[0] = new Image();
enemy1[0].src = "img/dj1.png";
enemy1[1] = new Image();
enemy1[1].src = "img/1.gif";
// 中飞机
var enemy2 = [];
enemy2[0] = new Image();
enemy2[0].src = "img/dj2.png";
enemy2[1] = new Image();
enemy2[1].src = "img/1.gif";
// 大飞机
var enemy3 = [];
enemy3[0] = new Image();
enemy3[0].src = "img/dj3.png";
enemy3[1] = new Image();
enemy3[1].src = "img/dj3.png";
enemy3[2] = new Image();
enemy3[2].src = "img/1.gif";
// 3.3.2 初始化敌方飞机的数据
var ENEMY1 = {
imgs : enemy1,
length : enemy1.length,
width : 90,
height : 69,
type : 1, //增加一个类型,判断是哪一种飞机
frame : 1,
life : 1,
score : 1
}
var ENEMY2 = {
imgs : enemy2,
length : enemy2.length,
width : 152,
height : 115,
type : 2, //增加一个类型,判断是哪一种飞机
frame : 1,
life : 5,
score : 5
}
var ENEMY3 = {
imgs : enemy3,
length : enemy3.length,
width : 197,
height : 134,
type : 3, //增加一个类型,判断是哪一种飞机
frame : 2,
life : 10,
score : 10
}
// 3.3.3 敌方飞机的构造函数
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){
// 根据飞机的状态来判定飞机是否由动画,就是要大飞机有动画效果
this.startIndex ++;
// 小飞机和中飞机就是0,大飞机是在0和1之间切换
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;
}
}
}
// 3.3.4 创建数组,用于存储敌方飞机
var enemies = [];
// 3.3.5 数组中去添加飞机
function pushEnemies(){
var numRand = Math.floor(Math.random() * 100);
if(numRand < 5){
enemies.push(new Enemy(ENEMY1))
}else if(numRand > 98){
enemies.push(new Enemy(ENEMY2))
}else if(numRand == 50){
enemies.push(new Enemy(ENEMY3))
}
}
// 3.3.6 敌方飞机的绘制函数
function paintEnemies(){
for(var i = 0;i < enemies.length;i++){
enemies[i].paint()
}
}
// 3.3.7 敌方飞机的运动函数
function stepEnemies(){
for(var i = 0;i < enemies.length;i++){
enemies[i].step()
}
}
// 3.3.8 敌方飞机的删除函数
function delEnemies(){
for(var i = 0;i < enemies.length;i++){
// 两种情况
if(enemies[i].y > HEIGHT || enemies[i].candel){
enemies.splice(i,1);
}
}
}
// 3.4 检测是否撞击
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();
}
}
}
}
// 3.5 文本函数
function paintText(){
context.font = "bold 30px 微软雅黑";
context.fillText("SCORE:" + score,20,20);
context.fillText("LIFE:" + life,300,20);
}
// 4 第四阶段 游戏暂停
canvas.onmouseout = function(){
if(state == RUNNING){
state = PAUSE;
}
}
canvas.onmouseover = function(){
if(state == PAUSE){
state = RUNNING;
}
}
var pause = new Image();
pause.src = "img/game_pause_nor.png";
// 5 第五阶段 游戏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 STARTTING:
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,246,350);
break;
case GAMEOVER:
hero.paint();
bulletsPaint();
paintEnemies();
paintText();
paintOver()
break;
}
},10)
</script>
</body>
</html>
实战效果: