<html>
<head>
<meta charset="UTF-8">
<title>打飞机</title>
<style type='css/text'>
* {
margin: 0;
padding: 0;
}
body {
overflow-x: hidden;
}
/*加载样式*/
#load {
/*background: url(../img/loading.gif) no-repeat center center;*/
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
#load div {
width: 100px;
height: 100px;
border-radius: 50%;
background: gray;
color: white;
line-height: 100px;
text-align: center;
font-size: 30px;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
}
#per {
color: white;
font-size: 30px;
}
#lt {
position: absolute;
left: 0;
top: 0;
display: none;
}
#score {
}
#game {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
width: 200px;
height: 150px;
border: 1px solid grey;
background: #ccc;
display: none;
text-align: center;
line-height: 50px;
}
a {
width: 100px;
height: 30px;
font-size: 20px;
/*border: 2px solid gray;*/
text-decoration: none;
color: red;
display: inline-block;
}
</style>
</head><body>
<!--整体思路
1.加载样式
2.背景图移动
3.玩家飞机 由于玩家只有一个所以可以使用对象的方式去设置,即设置一个对象
4.敌机 共三种 可以设置为一个类,即设置构造函数,可以使用该构造函数创建三个敌机类
5.弹夹类型,双弹,清屏弹,激光,也可以是一个类,即设置一个弹夹的构造函数
6.击中目标,子弹碰到敌机,矩形碰撞
7.被撞击,敌机撞到玩家飞机,矩形碰撞
8.计时器,计分器
-->
<!--加载样式-->
<div id="load">
<div><span id="per">0</span>%</div>
</div>
<canvas id="canvas" width="400" height="600"></canvas>
<!--设置音效-->
<audio id="gameMusic" src="audio/game_music.mp3" loop="loop" ></audio>
<audio id="gameOver" src="audio/game_over.mp3"></audio>
<audio id="bulletMusic" src="audio/bullet.mp3"></audio>
<audio id="boomMusic1" src="audio/enemy1_down.mp3"></audio>
<audio id="boomMusic2" src="audio/enemy2_down.mp3"></audio>
<audio id="boomMusic3" src="audio/enemy3_down.mp3"></audio>
<!--注意音频路径-->
<span id="score">0</span>分
</div>
<div id="game">游戏结束<br />得分:<span id="count"></span><br /><a href="http://127.0.0.1:8020/%E8%AF%BE%E5%A0%82%E4%BB%A3%E7%A0%81/JS/Day26-%E6%89%93%E9%A3%9E%E6%9C%BA%E6%B8%B8%E6%88%8F/game.html">重新开始</a></div>
</body>
<script type="text/javascript" charset="utf-8">
//获取id方法
function getId(id) {
return document.getElementById(id);
}
//设置img加载
var imgBox = ['img/background.png', 'img/bullet1.png', 'img/bullet2.png', 'img/enemy1.png', 'img/enemy2.png', 'img/enemy3.png', 'img/herofly.png', 'img/prop.png'];
//获取页面当中的dom节点
var canvas = getId("canvas");
var cx = canvas.getContext("2d");
//背景音乐
var gameMusic = getId("gameMusic"); //全局音乐
var gameOver = getId("gameOver"); //玩家死亡音乐
var bulletMusic = getId("bulletMusic"); //枪声
var boomMusic1 = getId("boomMusic1"); //小型敌机声音
var boomMusic2 = getId("boomMusic2"); //中型敌机声音
var boomMusic3 = getId("boomMusic3"); //大型敌机声音
//重新设置canvas大小,使其和window窗口一致
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
//加载图片
var imgLength = imgBox.length;
var count = 0; //声明循环次数
for (var i = 0; i < imgLength; i++) {
var img = new Image();
img.src = imgBox[i];
//加载完毕
img.onload = function() {
count++; //每加载一个就添加一次
//获取百分比
var per = Math.floor(count / imgLength * 100);
getId("per").innerHTML = per;
//判断是否加载90%
if (per >= 90) {
//去掉加载中效果
getId("load").style.display = "none";
//添加背景音乐,渲染气氛
gameMusic.play();
}
}
}
//加载图片
//背景图片
var bgImg = new Image();
bgImg.src = imgBox[0];
//玩家图片
var hero = new Image();
hero.src = imgBox[6];
//单行子弹图片
var dBullet = new Image();
dBullet.src = imgBox[1];
//两行子弹图片
var dBullet2 = new Image();
dBullet2.src = imgBox[2];
//道具图片
var prop = new Image();
prop.src = imgBox[7];
//敌机图片
var enemy1 = new Image();
enemy1.src = imgBox[3];
var enemy2 = new Image();
enemy2.src = imgBox[4];
var enemy3 = new Image();
enemy3.src = imgBox[5];
//背景图移动
var h = 0;
function moveBg() {
h++;
cx.drawImage(bgImg, 0, h, canvas.width, canvas.height);
cx.drawImage(bgImg, 0, h - canvas.height, canvas.width, canvas.height);
//判断复位
if (h >= canvas.height) {
h = 0;
}
}
//设置玩家
var Hero = {
h: 82, //玩家的高
w: 66, //玩家的宽
x: (canvas.width - 66) / 2,
y: canvas.height - 100,
bx: 0,
//绘制玩家
draw: function() {
cx.drawImage(hero, this.bx, 0, 66, 82, this.x, this.y, 66, 82);
}
};
//鼠标拖动事件
window.addEventListener("mousemove", function(event) {
var x = event.clientX - canvas.offsetLeft;
var y = event.clientY - canvas.offsetTop;
//把鼠标的位置给玩家
Hero.x = x - 33;
Hero.y = y - 35;
//防止事件冒泡和默认事件
event.stopPropagation();
event.preventDefault();
}, false);
//创建子弹类 x值,y值,宽,高,子弹类型,伤害值
function Bullet(x, y, w, h, buts, hurt) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.buts = buts;
this.hurt = hurt;
}
//存放子弹的数组
var bulletBox = [];
//控制子弹时间间隔,为索引值
var bulletNum = 0;
var box = 6;
//子弹移动
Bullet.prototype.move = function() {
bulletNum++;
if (bulletNum >= box) {
//单行子弹移动
var b = new Bullet(this.x, this.y, this.w, this.h, this.buts, this.hurt);
//把子弹放进弹夹
bulletBox.push(b);
bulletNum = 0;
}
//循环绘制数组中子弹
for (var i = 0; i < bulletBox.length; i++) {
var bb = bulletBox[i];
bb.y -= 5;
//到达顶部删除数组中的数据
if (bb.y <= -bb.h) {
bulletBox.splice(i, 1);
}
if (bb) {
//如果该元素没有从数组中删除则绘制子弹
cx.drawImage(bb.buts, bb.x, bb.y);
bulletMusic.play(); //给子弹加声音
}
}
};
//创建一个道具类 bx代表从道具图中哪个地方获取道具 speed代表下落速度
function Prop(x, y, w, h, bx, speed) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.bx = this.w * bx;
this.speed = speed;
}
//道具下落方法
Prop.prototype.move = function() {
this.y += this.speed;
//绘制道具
cx.drawImage(prop, this.bx, 0, this.w, this.h, this.x, this.y, this.w, this.h);
};
//创建敌机类
function EnemyPlane(x, y, w, h, type, hp, speed, die, score) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.type = type; //敌机类型
this.hp = hp; //剩余血量
this.speed = speed;
this.die = die; //死亡动画
this.score = score; //不同敌机不同分数
this.bx = 0;
this.bol = true; //判断是否爆炸
this.sayDie = false; //告诉程序对象的死亡状态,便于及时清除敌机残害
}
//敌机爆炸 也就是血量为0
EnemyPlane.prototype.boom = function() {
this.bol = false;
}
//敌机下落
EnemyPlane.prototype.move = function() {
//绘制敌机
if (this.bol) {
this.y += this.speed;
} else { //死亡
this.die--; //死亡动画执行的关键帧间隔
this.bx += this.w; //图片移动
if (this.die <= 0) { //告知死亡
this.sayDie = true;
}
}
//绘制敌机
cx.drawImage(this.type, this.bx, 0, this.w, this.h, this.x, this.y, this.w, this.h);
}
//定义初始值
var score = 0; //设置分数
var enemyArr = []; //设置敌机数组
var lifeBol = true; //玩家活着
var da = true; //判断是否是单双子弹,默认为单
var buttled; //声明子弹类型
var fire = 0; //替换飞机喷火
var heronum = 0;
var baoBol = true; //设置整个页面只有一个子弹包裹的布尔值
var bao; //子弹包裹
var timer = 0; //设置双排子弹出现的关键帧
//设置主函数
function main() {
//清除画布
cx.clearRect(0, 0, canvas.width, canvas.height);
//背景图移动
moveBg();
Hero.draw(); //绘制玩家
//添加敌机
var enemRan = randomNum(1, 5000); //获取添加敌机的概率
var butRan = randomNum(1, 3000);
var baoRan = randomNum(1, 3000); //获取添加子弹类型的概率
//判断敌机出现的位置
var x1 = randomNum(0, canvas.width - 38); //设置小敌机出现位置的x坐标
var x2 = randomNum(0, canvas.width - 46); //设置中敌机出现位置的x坐标
var x3 = randomNum(0, canvas.width - 110); //设置大敌机出现位置的x坐标
var x4 = randomNum(0, canvas.width - 38); //设置弹夹出现位置的x坐标
var enemySpeed = randomNum(5, 10); //设置敌机速度
//创建敌机
if (enemRan < 200) {
//创建小敌机
enemyArr.push(new EnemyPlane(x1, -34, 38, 34, enemy1, 1, 5, 5, 10));
}
if (enemRan > 40 && enemRan < 80) {
//创建中敌机
enemyArr.push(new EnemyPlane(x2, -64, 46, 64, enemy2, 3, 4, 6, 50));
}
if (enemRan > 100 && enemRan < 110) {
//创建大敌机
enemyArr.push(new EnemyPlane(x3, -164, 110, 164, enemy3, 7, 2, 10, 100));
}
//创建子弹
var hx = Hero.x;
var hy = Hero.y;
if (lifeBol) { //玩家活着
fire++; //当飞机正常飞行的时候,改变图的位置,显示喷火效果
if (fire > 1) {
fire = 0;
}
Hero.bx = Hero.w * fire;
if (da) { //单行子弹
//创建单行子弹 6*14
buttled = new Bullet(hx + 30, hy - 14, 6, 14, dBullet, 10);
} else { //双行子弹
buttled = new Bullet(hx + 9, hy - 14, 48, 14, dBullet2, 20);
}
buttled.move();
} else { //如果英雄死亡
//清空子弹数组
bulletBox.length = 0;
heronum++;
if (heronum % 10 == 0) {
Hero.bx = Math.floor(heronum / 10) * Hero.w;
}
}
//遍历enemyArr数组 添加敌机
for (var i = 0; i < enemyArr.length; i++) {
//遍历子弹数组
for (var j = 0; j < bulletBox.length; j++) {
if (enemyArr[i].bol) {
//判断子弹与敌机相撞
if (crash(enemyArr[i], bulletBox[j])) {
//子弹碰到敌机
enemyArr[i].hp -= bulletBox[j].hurt;
if (enemyArr[i].hp < 0) {
enemyArr[i].boom(); //执行爆炸
}
//根据每个敌机携带的分数,判断敌机类型,获取相应的分数,添加声音
if (enemyArr[i].score == 10) {
//小型机
boomMusic1.play();
} else if (enemyArr[i].score == 50) {
//中型机
boomMusic2.play();
} else if (enemyArr[i].score == 100) {
//大型机
boomMusic3.play();
}
//添加分数
score += enemyArr[i].score;
//删除子弹
bulletBox.splice(j, 1);
}
}
}
//检测玩家撞到了飞机
if (crash(enemyArr[i], Hero) && lifeBol) {
lifeBol = false; //玩家死亡
gameOver.play(); //结束音乐响起
gameMusic.pause(); //背景音乐暂停
getId("game").style.display = "block";
}
//删除没有碰到子弹和飞机的敌机
if (enemyArr[i].y > canvas.height) {
enemyArr.splice(i, 1);
}
//绘制敌机
if (enemyArr[i]) {
enemyArr[i].move();
//检测敌机动画执行完毕
if (enemyArr[i].sayDie) {
enemyArr.splice(i, 1); //删除敌机
}
}
//添加子弹包裹
//console.log(butRan < 100 , baoBol);
if (butRan < 100 && baoBol) { //满足概率,并且添加true
baoBol = false;
var typeNum = baoRan < 50 ? 0 : 1;
bao = new Prop(x4, -68, 38, 68, typeNum, 0.5);
}
//当baoBol为false的时候
if (!baoBol && bao) {
bao.move();
//当包裹超出canvas范围时消失 可以重新设置包裹
if (bao && bao.y > canvas.height) {
baoBol = true;
}
//当包裹和玩家碰撞的时候消失
if (crash(bao, Hero) && lifeBol) {
baoBol = true;
if (bao.bx == 0) { //碰到了清屏弹
for (var k = 0; k < enemyArr.length; k++) {
enemyArr[k].boom(); //每一个都要执行爆炸方法
if (enemyArr[k].score == 10) {
boomMusic1.play();
} else if (enemyArr[k].score == 50) {
boomMusic2.play();
} else {
boomMusic3.play();
}
//加分
if (enemyArr[k].sayDie) {
score += enemyArr[k].score;
enemyArr.splice(k, 1);
}
}
} else if (bao.bx == 38) { //碰到了双弹
da = false;
timer = 0;
}
}
}
if (!da) {
timer++;
if (timer > 3000) {
da = true;
timer = 0;
}
}
}
//设置分数
getId("score").innerHTML = score;
getId("count").innerHTML = score;
//执行动画
requestAnimationFrame(main);
}
//页面资源加载完毕后执行
window.onload = function() {
//执行主函数
main();
}
//随机数
function randomNum(x, y) {
return Math.floor(Math.random() * (y - x + 1) + x);
}
//碰撞检测 (矩形碰撞检测)
function crash(obj1, obj2) {
var x1 = obj1.x;
var y1 = obj1.y;
var rx1 = obj1.x + obj1.w / 2;
var ry1 = obj1.y + obj1.h / 2;
var x2 = obj2.x;
var y2 = obj2.y;
var rx2 = obj2.x + obj2.w / 2;
var ry2 = obj2.y + obj2.h / 2;
//判断碰撞
if (Math.abs(rx1 - rx2) <= (obj1.w + obj2.w) / 2 && Math.abs(ry1 - ry2) <= (obj1.h + obj2.h) / 2) {
return true;
} else {
return false;
}
}
</script>
</html>