canvas实习飞机大战小游戏
具体实现代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>飞机大战</title>
<style>
canvas {
border: 1px solid;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas width="500px" height="800px"></canvas>
<script>
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext("2d");
// 初始化数据
var START = 0;
var STARTING = 1;
var RUNNING = 2;
var PAUSE = 3;
var GAMEOVER = 4;
// 记录游戏的状态变化
var state = START;
// 获取画布的宽和高
var HEIGHT = canvas.height;
var WIDTH = canvas.width;
// 游戏的分数
var score = 0;
// 我方飞机的生命值
var life = 3;
// 将游戏分为几个阶段
// 1 准备阶段 使用定时器绘制背景图和logo
// 1.1 运动的背景图片
// 1.1.1创建图片对象
var bg = new Image();
bg.src = "img/background.png"
// 定义图片信息
var BG = {
width: WIDTH,
height: HEIGHT,
img: bg
}
// 创建背景图片的构造函数
function Bg(parmas) {
this.width = parmas.width;
this.height = parmas.height;
this.img = parmas.img;
// 绘制图片的坐标
this.x = 0;
this.y = 0;
this.x1 = 0;
this.y1 = -this.height;
// 定义绘制图片的方法
this.paint = function () {
ctx.drawImage(this.img, this.x, this.y, this.width, this.height)
ctx.drawImage(this.img, this.x1, this.y1, this.width, this.height)
}
// 图片的运动
this.step = function () {
this.y += 10;
this.y1 += 10;
if (this.y1 >= this.height) {
this.y1 = -this.height;
}
if (this.y >= this.height) {
this.y = -this.height;
}
}
}
var sky = new Bg(BG)
// 1.2 logo
// 1.2.1创建logo对象
var logo = new Image();
logo.src = "img/start.png"
// 2 游戏加载阶段 点击画布触发开始游戏
// 2.1点击canvas触发当前状态
canvas.onclick = function () {
if (state == START) {
state = STARTING;
}
}
// 2.2 绘制我方飞机
// 把图片的地址存入数组中
var imgArr = ["img/game_loading1.png", "img/game_loading2.png", "img/game_loading3.png",
"img/game_loading4.png"
]
var img = [];
for (var i = 0; i < imgArr.length; i++) {
img[i] = new Image();
img[i].src = imgArr[i]
}
var LOADING = {
imgs: img,
length: img.length,
width: 186,
height: 38
}
// 创建构造函数
function Loading(parmas) {
this.imgs = parmas.imgs;
this.length = parmas.length;
this.width = parmas.width;
this.height = parmas.height;
// 记录当前照片索引值
this.startIndex = 0;
// 开始绘制
this.paint = function () {
// console.log(loading);
ctx.drawImage(this.imgs[this.startIndex], 0, HEIGHT - this.height)
this.startIndex++;
if (this.startIndex == this.length) {
state = RUNNING;
}
}
}
var loading = new Loading(LOADING)
// 3 游戏进行中 游戏加载完成后进入该阶段
// 3.1 我方飞机跟随鼠标移动包括子弹的发射
// 3.1.1创建我方飞机
var heros = ['img/hero1.png', 'img/hero2.png', 'img/hero_blowup_n1.png', 'img/hero_blowup_n2.png',
'img/hero_blowup_n3.png', 'img/hero_blowup_n4.png'
];
var img = [];
for (var i = 0; i < heros.length; i++) {
img[i] = new Image();
img[i].src = heros[i];
}
// 3.1.2我方飞机详细信息
var HEROS = {
imgs: img,
length: img.length,
width: 99,
height: 124,
frame: 2 //记录飞行状态
}
// 3.1.2我方飞机构造函数
function Heros(parmas) {
this.imgs = parmas.imgs;
this.length = parmas.length;
this.width = parmas.width;
this.height = parmas.height;
this.frame = parmas.frame;
// 索引记录当前飞机的下标
this.startIndex = 0;
//飞机的坐标
this.x = WIDTH / 2 - this.width / 2;
this.y = HEIGHT - this.height - 10;
this.paint = function () {
ctx.drawImage(this.imgs[this.startIndex], this.x, this.y)
}
// 记录是否发生了碰撞,false表示没有,true有
this.down = false;
// 定义飞机是否爆破完成,表示飞机还没有完全爆炸
this.candel = false;
// 我方飞机运动方法
this.step = function () {
if (this.down) {
this.startIndex++;
// 在碰撞的动画执行完成后
if (this.startIndex == this.length) {
life--;
// 检查生命值是否为0
if (life == 0) {
state = GAMEOVER;
this.startIndex = this.length - 1;
} else {
hero = new Heros(HEROS);
}
}
} else {
//正常状态,没有发生碰撞
//切换索引0/1
if (this.startIndex == 0) {
this.startIndex = 1;
} else {
this.startIndex = 0;
}
}
}
// 碰撞方法
this.bang = function () {
this.down = true;
}
this.time = 0
//射击方法
this.shoot = function () {
this.time++;
if (this.time % 3 == 0) {
// 子弹的数组里面添加子弹对象
bullets.push(new Bullet(BULLET));
}
}
}
var hero = new Heros(HEROS);
//3.1.4飞机跟鼠标移动
canvas.addEventListener("mousemove", function (e) {
// 获取鼠标的触发事件的当前位置
var x = e.offsetX;
var y = e.offsetY;
// 将值赋值给飞机的x,y坐标
if (state == RUNNING) {
hero.x = x - hero.width / 2;
hero.y = y - hero.height / 2;
}
})
// 3.1.5 绘制子弹
var bullet = new Image();
bullet.src = 'img/bullet1.png';
var BULLET = {
img: bullet,
width: 9,
height: 21
}
//子弹构造
function Bullet(parmas) {
this.img = parmas.img;
this.width = parmas.width;
this.height = parmas.height;
// 坐标
this.x = hero.x + hero.width / 2 - this.width / 2;
this.y = hero.y - this.height;
//绘制方法
this.paint = function () {
ctx.drawImage(this.img, this.x, this.y)
}
//子弹移动
this.step = function () {
this.y -= 10;
}
// 判断子弹是否碰撞
this.candel = false;
// 子弹碰撞方法
this.bang = function () {
this.candel = true;
}
}
// 创建子弹数组
var bullets = [];
// 遍历绘制子弹
function bulletdPaint() {
for (var i = 0; i < bullets.length; i++) {
bullets[i].paint();
}
};
// 遍历调用子弹的运动;
function bulletdStep() {
for (var i = 0; i < bullets.length; i++) {
bullets[i].step();
}
};
// 子弹的删除函数
function bulletDel() {
// 碰撞的时候删除子弹
// 超出画布的高度,即负的子弹的高度
for (var i = 0; i < bullets.length; i++) {
if (bullets[i].candel || bullets[i].y < -bullets[i].height) {
bullets.splice(i, 1)
}
}
};
// 3.2 随机绘制敌机
// 绘制小飞机
var enemy1Arr = ["img/enemy1.png", "img/enemy1_down1.png", "img/enemy1_down2.png", "img/enemy1_down3.png",
"img/enemy1_down4.png"
]
var enemy1 = [];
for (var i = 0; i < enemy1Arr.length; i++) {
enemy1[i] = new Image();
enemy1[i].src = enemy1Arr[i];
}
var ENEMY1 = {
imgs: enemy1,
length: enemy1.length,
width: 57,
height: 51,
type: 1,
frame: 1,
life: 1,
score: 1,
};
//绘制中飞机
var enemy2Arr = ["img/enemy2.png", "img/enemy2_down1.png", "img/enemy2_down2.png", "img/enemy2_down3.png",
"img/enemy2_down4.png"
]
var enemy2 = [];
for (var i = 0; i < enemy2Arr.length; i++) {
enemy2[i] = new Image();
enemy2[i].src = enemy2Arr[i];
}
var ENEMY2 = {
imgs: enemy2,
length: enemy2.length,
width: 69,
height: 95,
type: 2,
frame: 1,
life: 5,
score: 5,
};
// 绘制大飞机
var enemy3Arr = ["img/enemy3_n1.png", "img/enemy3_n2.png", "img/enemy3_down1.png", "img/enemy3_down2.png",
"img/enemy3_down3.png",
"img/enemy3_down4.png", "img/enemy3_down5.png", "img/enemy3_down6.png"
]
var enemy3 = [];
for (var i = 0; i < enemy3Arr.length; i++) {
enemy3[i] = new Image();
enemy3[i].src = enemy3Arr[i];
}
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; // 用于判断的下标
this.down = false; // 用于判断是否碰撞
this.candel = false; // 用于判断是否爆炸完成
//绘制方法
this.paint = function () {
ctx.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 += 2;
} else {
//飞机发生碰撞以后
this.startIndex++;
if (this.startIndex == this.length) {
this.candel = true;
this.startIndex = this.length - 1;
}
}
};
// 判断是否被碰撞
this.checkHit = function (wo) {
//判断四个边
return wo.y + wo.height > this.y &&
wo.x + wo.width > this.x &&
wo.y < this.y + this.height &&
wo.x < this.x + this.width;
};
//敌方飞机碰撞后
this.bang = function () {
this.life--;
if (this.life === 0) {
this.down = true;
score += this.score;
}
}
};
// 数组存放敌方飞机
var enemise = [];
// 往敌方飞机数组中添加数据
function enterEnemise() {
var rand = Math.floor(Math.random() * 100)
if (rand < 10) {
// 添加小飞机
enemise.push(new Enemy(ENEMY1));
} else if (rand < 55 && rand > 50) {
// 添加中飞机
enemise.push(new Enemy(ENEMY2));
} else if (rand === 88) {
// 添加大飞机
if (enemise[0].type !== 3 && enemise.length > 0) {
enemise.splice(0, 0, new Enemy(ENEMY3));
}
}
};
// 绘制敌方飞机函数
function enemyPaint() {
for (var i = 0; i < enemise.length; i++) {
enemise[i].paint();
}
};
// 敌方飞机的运动函数
function enemyStep() {
for (var i = 0; i < enemise.length; i++) {
enemise[i].step();
}
};
// 删除敌方飞机函数
function delenemy() {
for (var i = 0; i < enemise.length; i++) {
// console.log(enemise[i].candel)
if (enemise[i].y > HEIGHT || enemise[i].candel) {
enemise.splice(i, 1)
}
}
};
// 碰撞以后的函数
function hitEnemise() {
for (var i = 0; i < enemise.length; i++) {
// 如果我放飞机撞到了敌方飞机以后
if (enemise[i].checkHit(hero)) {
// 敌方飞机碰撞后,碰撞状态改变
enemise[i].bang();
// 我方飞机碰撞后,碰撞状态改变
hero.bang();
};
// 子弹碰到敌方飞机
for (var j = 0; j < bullets.length; j++) {
if (enemise[i].checkHit(bullets[j])) {
enemise[i].bang();
// 子弹的碰撞后,碰撞状态改变
bullets[j].bang();
}
}
}
};
// 绘制分数和生命值
function scoreText() {
ctx.font = "30px bold"
ctx.fillText("分数:" + score, 10, 30);
ctx.fillText("生命:" + life, 300, 30);
};
// 游戏结束
function gameoverfn() {
ctx.font = "50px bold"
ctx.fillText("GAME OVER !!!", 80, 300);
ctx.fillText("ONCE MORE !!!", 80, 400);
};
canvas.addEventListener("click", function (e) {
p = getEventPosition(e);
// 点击画布时,判断游戏是否开始
if (state === START){
state = STARTING;
}
// 重新开始游戏有问题???
if (state === GAMEOVER) {
if (p.y >= 350 && p.y < 450) {
history.go(0);
}
}
});
function getEventPosition(e) {
var x, y;
if (e.layerX || ev.layerX === 0) {
x = e.layerX;
y = e.layerY;
} else if (e.offsetX || ev.offsetX === 0) {
x = e.offsetX;
y = e.offsetY;
}
return {
x: x,
y: y
};
};
// 4 暂停阶段 鼠标离开画面 进入该阶段
// 4.1 敌方飞机 我方飞机以及子弹静止
canvas.onmouseleave = 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";
// 4.2 鼠标移入画布 游戏结束,恢复到第三阶段
// 5 我方飞机发生了爆炸 地方飞机静止
// 定时器
var timer = setInterval(function () {
sky.paint();
sky.step();
switch (state) {
case START:
ctx.drawImage(logo, 0, 0, WIDTH, HEIGHT);
break;
case STARTING:
loading.paint();
// loading.step()
break;
case RUNNING:
hero.paint();
// 我方飞机的运动
hero.step();
// 我方飞机的射击方法
hero.shoot();
// 子弹的绘制
bulletdPaint();
// 子弹的运动
bulletdStep();
// 子弹的删除
bulletDel();
// 创建敌方飞机
enterEnemise();
// 绘制敌方飞机
enemyPaint();
// 绘制敌方飞机的运动
enemyStep();
// 删除敌方飞机
delenemy();
// 判断是否撞击
hitEnemise();
// 绘制分数和生命值
scoreText()
break;
case PAUSE:
sky.paint(); // 绘制背景
sky.step(); // 背景动画
// 绘制我放飞机
hero.paint();
// 子弹的绘制
bulletdPaint();
// 绘制敌方飞机
enemyPaint();
// 绘制分数和生命值
scoreText();
ctx.drawImage(pause, 220, 300)
break;
case GAMEOVER:
sky.paint(); // 绘制背景
sky.step(); // 背景动画
hero.paint();
// 子弹的绘制
bulletdPaint();
// 绘制敌方飞机
enemyPaint();
// 绘制分数和生命值
scoreText();
// 游戏结束
gameoverfn();
}
}, 30)
</script>
</body>
</html>