css样式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
canvas {
display: block;
margin: 50px auto;
border: 1px solid black;
}
</style>
</head>
<body>
<canvas width="480" height="600"></canvas>
<script src="./index.js">
</script>
</body>
</html>
js部分:
// 获取画布画笔
var canvas = document.getElementsByTagName('canvas')[0]
var ctx = canvas.getContext('2d')
// 初始化游戏数据 画布数据 背景图片数据 阶段数据
var canWidth = canvas.width
var canHeight = canvas.height
// 初始化各个游戏阶段数据
// 开始
var start = 0
// 加载
var ready = 1
// 游戏中
var playing = 2
// 暂停
var pause = 3
// 游戏结束
var over = 4
// 定义一个变量用以记录游戏状态(状态码)
var state = start
// 分数
var score = 0
// 生命值
var lives = 3
// 准备阶段
// 绘制背景图片
var bgimg = new Image()
// 设置图片地址
bgimg.src = 'img/background.png'
// 设置一个背景图片对象,存储图片数据
var bgi = {
// 图片对象名称
img: bgimg,
// 宽高
width: 480,
height: 600,
}
// 定义一个构造函数创建背景图片对象
function bg(config) {
// 图片的基本属性
this.img = config.img;
this.width = config.width;
this.height = config.height;
// 图片坐标
this.x = 0;
this.y = 0;
// 定义第二张的坐标
this.x1 = 0;
this.y1 = -this.height;
// 绘制方法
this.paint = function () {
// 实现无缝衔接绘制两张 一张放在画布上方
ctx.drawImage(this.img, this.x, this.y);
ctx.drawImage(this.img, this.x1, this.y1);
}
// 运动方法
// 移动到底后位置回到画布上方
this.sport = function () {
// 移动速度
this.y += 1;
this.y1 += 1;
if (this.y > this.height) {
this.y = -this.height;
}
if (this.y1 > this.height) {
this.y1 = -this.height;
}
}
}
// 实例化背景图片对象
var backImg = new bg(bgi)
// 绘制标题图片
var titleImg = new Image()
// 设置标题图片地址
titleImg.src = 'img/start.png'
// 创建对象存储标题图片属性
var timg = {
img: titleImg,
width: 480,
height: 600
}
// 创建一个构造函数 绘制标题
function tit(config) {
this.img = config.img
this.width = config.width
this.height = config.height
this.x = 40
this.y = 0
// 绘制方法
this.paint = function () {
ctx.drawImage(this.img, this.x, this.y);
}
}
// 实例化标题图片对象
var t = new tit(timg)
// 点击开始游戏
canvas.onclick = function () {
// 如果游戏状态处于开始阶段
if (state === start) {
// 切换游戏状态至准备阶段
state = ready
}
}
// 加载阶段
var imgs = 'game_loading'
var loading = []
for (var i = 0; i < 4; i++) {
loading[i] = new Image()
// 拼接图片地址
loading[i].src = `img/${imgs}${i + 1}.png`
}
// 创建图片对象
var Loading = {
img: loading,
width: 186,
height: 38,
length: loading.length
}
// 创建一个构造函数 绘制加载阶段图片
function Load(config) {
this.img = config.img
this.width = config.width
this.height = config.height
this.x = 0
this.y = canHeight - this.height
this.time = 0
this.Index = 0
this.length = config.length
// 绘制加载阶段图片
this.paint = function () {
ctx.drawImage(this.img[this.Index], this.x, this.y)
}
// 加载图片的运动方法
this.sport = function () {
this.time++
if (this.time % 3 == 0) {
this.Index++
}
if (this.Index == this.length) {
state = playing
}
}
}
// 实例化加载图片对象
var loadfour = new Load(Loading)
// 用数组储存图片地址
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 heroObj = []
// 循环创建我方飞机图片对象,对相应图片地址赋值
for (var i = 0; i < heros.length; i++) {
heroObj[i] = new Image();
heroObj[i].src = heros[i]
}
// 我方飞机数据
var heroplane = {
img: heroObj,
width: 99,
height: 124,
length: heroObj.length,
}
// 绘制我方飞机
function Hero(config) {
this.img = config.img
this.width = config.width
this.height = config.height
this.length = config.length
this.x = (canWidth - this.width) / 2
this.y = canHeight - this.height - 100
this.Index = 0
this.boom = false
this.time = 0
this.paint = function () {
ctx.drawImage(this.img[this.Index], this.x, this.y)
}
// 我方飞机运动方法
this.sport = function () {
if (this.boom) {
this.Index++
if (this.Index == this.length) {
lives--
this.boom = false
this.Index = 0
if (lives == 0) {
state = over
this.Index = this.length - 1
}
}
} else {
if (this.Index == 0) {
this.Index = 1
} else {
this.Index = 0
}
}
}
// 子弹的射击方案
this.shoot = function () {
// 用变量控制子弹输出频率 每刷新三次发射一次子弹
if (this.time % 3 == 0) {
// 将创建的子弹对象存入弹夹数组
bulletbox.push(new Bullet(bulletObj))
}
this.time++
}
}
// 实例化我方飞机对象
var hero = new Hero(heroplane)
// 子弹部分
// 创建子弹图片对象
var bullet = new Image()
bullet.src = 'img/bullet1.png'
var bulletObj = {
img: bullet,
width: 9,
height: 21
}
// 绘制子弹函数
function Bullet(config) {
this.img = config.img
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.bang = false
this.paint = function () {
ctx.drawImage(this.img, this.x, this.y)
}
this.sport = function () {
this.y -= this.height
}
}
var bullets = new Bullet(bulletObj)
// 创建数组存储所以绘制的子弹图片对象
var bulletbox = []
// 子弹绘制方法
function bulletPaint() {
for (var i = 0; i < bulletbox.length; i++) {
bulletbox[i].paint()
}
}
// 子弹运动方法
function bulletSport() {
for (var i = 0; i < bulletbox.length; i++) {
bulletbox[i].sport()
}
}
// 删除子弹
function bulletDelete() {
for (var i = 0; i < bulletbox.length; i++) {
// 当子弹超出屏幕范围或者命中后删除子弹
if (bulletbox[i].y <= -bulletbox[i].height || bulletbox[i].bang) {
bulletbox.splice(i, 1)
}
}
}
// 绘制敌机
// 小敌机
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 enemy1Obj = {
img: enemy1,
height: 51,
width: 57,
length: enemy1Arr.length,
life: 2,
type: 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 enemy2Obj = {
img: enemy2,
height: 95,
width: 69,
length: enemy2Arr.length,
life: 10,
type: 1, //设置类型状态码用以判断敌机类型
score: 5
}
// 大敌机
var enemy3Arr = ['img/enemy3_n1.png', 'img/enemy3_n2.png', 'img/enemy3_hit.png', 'img/enemy3_down1.png', 'img/enemy3_down2.png', 'img/enemy3_down3.png', 'img/enemy3_down4.png']
var enemy3 = []
for (var i = 0; i < enemy3Arr.length; i++) {
enemy3[i] = new Image()
enemy3[i].src = enemy3Arr[i]
}
//大敌机的对应数据
var enemy3Obj = {
img: enemy3,
height: 258,
width: 169,
length: enemy3Arr.length,
life: 20,
type: 2, //设置类型状态码用以判断敌机类型
score: 10
}
// 构造函数 绘制敌机
function Enemy(config) {
this.img = config.img
this.width = config.width
this.height = config.height
this.length = config.length
this.life = config.life
this.type = config.type
this.x = Math.random() * (canWidth - this.width)
this.y = -this.height
this.Index = 0
this.down = false
this.boom = false
this.time = 0
this.score = config.score
this.paint = function () {
ctx.drawImage(this.img[this.Index], this.x, this.y)
}
// 敌机运动方法
this.sport = function () {
// 受击状态
if (this.down) {
this.life--
if (this.life < 0) {
this.Index++
if (this.Index == this.length - 1) {
this.Index = this.length - 1
this.boom = true
score += this.score
}
}
}
// 正常状态
if (!this.down) {
if (this.type == 2) {
this.Index = this.Index == 0 ? 1 : 0
}
}
this.y += 2
}
// 判断自身是否被碰撞
this.chenckhit = function (my) {
return my.x > this.x && my.x < this.x + this.width && my.y <= this.y + this.height && my.y > 0
}
}
// 定义敌方飞机对象数组
var enemyFleet = []
// 往数组中添加不同型号的敌机
function createEnemy() {
var random = Math.random()
// 设置不同型号敌机出现概率
if (random < 0.08) {
enemyFleet.push(new Enemy(enemy1Obj))
} else if (random < 0.1) {
enemyFleet.push(new Enemy(enemy2Obj))
} else if (random < 0.12) {
enemyFleet.push(new Enemy(enemy3Obj))
}
}
// 敌机绘制方法
function enemyPaint() {
for (var i = 0; i < enemyFleet.length; i++) {
enemyFleet[i].paint();
}
}
// 敌机运动方法
function enemySport() {
for (var i = 0; i < enemyFleet.length; i++) {
enemyFleet[i].sport()
}
}
// 删除敌机
function enemyDelete() {
for (var i = 0; i < enemyFleet.length; i++) {
if (enemyFleet[i].boom || (enemyFleet[i].y >= canHeight)) {
enemyFleet.splice(i, 1)
}
}
}
// 封装一个函数判断是否发生碰撞
function hit() {
for (var i = 0; i < enemyFleet.length; i++) {
if (enemyFleet[i].chenckhit(hero)) {
// 发生碰撞则将我方飞机碰撞状态改为true
hero.boom = true
}
for (var j = 0; j < bulletbox.length; j++) {
if (enemyFleet[i].chenckhit(bulletbox[j])) {
// 将子弹命中状态,与敌机受击状态改为true
bulletbox[j].bang = true
enemyFleet[i].down = true
enemyFleet[i].y += 0
}
}
}
}
// 鼠标移出事件 移出暂停
canvas.onmouseout = function () {
if (state == playing) {
state = pause
}
}
// 鼠标移入事件 移入游戏继续
canvas.onmouseover = function () {
if (state == pause) {
state = playing
}
}
// 移动事件,让飞机跟随鼠标移动
canvas.onmousemove = function (e) {
var x = e.offsetX
var y = e.offsetY
if (state === playing) {
hero.x = x - hero.width / 2
hero.y = y - hero.height / 2
}
}
// 暂停阶段
var pauseImg = new Image()
pauseImg.src = 'img/game_pause_nor.png'
var paused = {
img: pauseImg,
width: 60,
height: 45
}
// 绘制暂停图片
function Pause(config) {
this.img = config.img
this.width = config.width
this.height = config.height
this.x = canWidth / 2 - this.width / 2
this.y = canHeight / 2 - this.height / 2
this.paint = function () {
ctx.drawImage(this.img, this.x, this.y)
}
}
// 实例化暂停图片对象
var pause = new Pause(paused)
// 游戏结束阶段
function paintOver() {
ctx.font = "bold 50px 微软雅黑";
ctx.fillText("游戏结束!", 130, 300);
}
// 飞机的生命值与得分
function paintText() {
ctx.font = "bold 30px 微软雅黑";
ctx.fillText("SCORE:" + score, 10, 30);
ctx.fillText("LIFE:" + lives, 380, 30)
}
setInterval(function () {
// 绘制背景
backImg.paint();
backImg.sport();
if (state === start) {
// 准备阶段绘制LOGO
t.paint()
} else if (state === ready) {
// 加载阶段绘制加载图片
loadfour.paint()
loadfour.sport()
} else if (state === playing) {
// 游戏进行中
// 绘制我方灰机
hero.paint()
hero.sport()
hero.shoot()
// 绘制子弹
bulletPaint()
bulletSport()
bulletDelete()
// 绘制敌机
enemyPaint()
createEnemy()
enemySport()
enemyDelete()
hit()
// 当前生命值与分数
paintText()
} else if (state === pause) {
// 暂停阶段 停止运动
hero.paint()
bulletPaint()
enemyPaint()
pause.paint()
paintText()
} else if (state === over) {
// 结束阶段 停止运动 绘制游戏结束文本
paintOver()
hero.paint()
bulletPaint()
enemyPaint()
paintText()
}
}, 20)
|