又到了每日分享時(shí)間了,今天分享的內(nèi)容為:JavaScript打飛機(jī)小游戲
效果圖:
實(shí)現(xiàn)邏輯:
第一步:實(shí)現(xiàn)頁面的排版窗骑、布局
1.1 準(zhǔn)備打飛機(jī)游戲需要使用到的圖片
1.2 開始游戲界面
1.3 進(jìn)入游戲的界面
1.3.1 己方飛機(jī)
1.3.2 敵方飛機(jī)
1.3.3 己方飛機(jī)發(fā)射的子彈
第二步:開始游戲
2.1 點(diǎn)擊開始游戲按鈕擎淤,進(jìn)入到游戲界面
2.2 摁下空格鍵嘁锯,實(shí)現(xiàn)己方飛機(jī)跟隨鼠標(biāo)的移動==》游戲的開始
2.3 第二次摁下空格鍵時(shí)皱卓,實(shí)現(xiàn)己方飛機(jī)的暫停移動==》游戲的暫停
2.4 以此類推进宝,實(shí)現(xiàn)開始和暫停的交換
第三步:開始游戲之后的發(fā)射子彈
3.1 定時(shí)創(chuàng)建子彈:
3.1.1 單位時(shí)間內(nèi)創(chuàng)建子彈的數(shù)量
3.1.2 開始游戲和暫停游戲時(shí):暫停游戲后官卡,不能再創(chuàng)建子彈蝗茁;再次開始游戲時(shí),不能存在多個(gè)創(chuàng)建子彈的定時(shí)器==》把上一次創(chuàng)建子彈的定時(shí)器給清除或者不再開啟定時(shí)器
3.2 制造子彈
3.2.1 制造子彈時(shí)寻咒,確定子彈的位置
3.2.2 根據(jù)當(dāng)前己方飛機(jī)的位置
3.2.3 把子彈追加到文檔中去
3.3 子彈的運(yùn)動
3.3.1 子彈的top值是-子彈的高度時(shí)哮翘,刪除子彈,清除定時(shí)器
3.4 子彈消失
3.4.1 子彈飛出游戲界面
3.4.2 清除子彈==》每一顆飛出到游戲界面之外的子彈仔涩,肯定是第一個(gè)創(chuàng)建的子彈(當(dāng)前子彈所在父元素下的第一個(gè)子元素)
第四步:開始游戲之后的創(chuàng)建敵機(jī)
4.1 定時(shí)創(chuàng)建敵機(jī)
4.1.1 單位時(shí)間內(nèi)創(chuàng)建敵機(jī)的數(shù)量
4.1.2 暫停之后不能重復(fù)性的開啟創(chuàng)建敵機(jī)的定時(shí)器
4.1.3 敵機(jī)的概率出現(xiàn):大忍坷、中、小三種敵機(jī)
===》腥壑:75% 中:20% 大:5%
4.2 制造敵機(jī)
4.3 敵機(jī)的運(yùn)動
4.4 敵機(jī)的消失
第五步:實(shí)現(xiàn)游戲的暫停
5.1 敵機(jī)運(yùn)動速度的控制
5.2 實(shí)現(xiàn)游戲的暫停
5.2.1 清除己方飛機(jī)的移動
5.2.2 清除創(chuàng)建敵機(jī)
5.2.3 清除創(chuàng)建子彈
5.2.4 清除每顆子彈上的運(yùn)動
5.2.5 清除每架敵機(jī)上的運(yùn)動
第六步:實(shí)現(xiàn)開始游戲之后的背景圖的運(yùn)動
6.1 改變的是背景圖的background-position-y的值
6.2 游戲界面的高度568佩研,每運(yùn)動568px是一個(gè)循環(huán)
第七步:檢測子彈和敵機(jī)的碰撞
7.1 每一個(gè)敵機(jī)都是運(yùn)動的,每一顆子彈也是運(yùn)動的==》在每一架敵機(jī)運(yùn)動時(shí)霞揉,檢測和所有游戲界面內(nèi)存在的子彈的碰撞
7.2 創(chuàng)建全局變量:把當(dāng)前游戲界面內(nèi)存在的所有的子彈放入到該變量里
7.3 敵機(jī)運(yùn)動的過程中旬薯,檢測和每一顆子彈的碰撞
7.4 子彈和敵機(jī)發(fā)生碰撞時(shí),子彈消失
7.4.1 把該子彈元素刪除掉
7.4.2 把該子彈元素從全局變量集合里刪除
7.5 敵機(jī)和子彈發(fā)生碰撞時(shí)适秩,敵機(jī)血量減少==》每一顆子彈消耗的血量100
7.6 敵機(jī)的血量為0時(shí)绊序,刪除敵機(jī)元素?秽荞?骤公?
第八步:實(shí)現(xiàn)敵機(jī)的爆炸效果
8.1 替換爆炸圖片
8.2 區(qū)分存活的敵機(jī)和死亡敵機(jī)(爆炸過程中的敵機(jī))==》標(biāo)記每一架敵機(jī)的存活狀態(tài)
8.3 延時(shí)刪除敵機(jī)元素==》顯示爆炸效果
8.4 在創(chuàng)建敵機(jī)時(shí),刪除敵機(jī)集合中的死亡敵機(jī)
第九步:實(shí)現(xiàn)游戲的得分
第十步:檢測己方飛機(jī)和敵機(jī)的碰撞
10.1 一對多的關(guān)系:敵機(jī)運(yùn)動扬跋,己方飛機(jī)運(yùn)動
10.2 在每一架敵機(jī)運(yùn)動的過程中檢測
10.3 碰撞的原理
第十一步:游戲結(jié)束
11.1 清除掉當(dāng)前頁面上的所有的定時(shí)器
11.2 清除掉所有子彈上的定時(shí)器以及刪除所有的子彈元素
11.3 清除掉素有敵機(jī)上的定時(shí)器以及刪除所有的敵機(jī)元素
11.4 清空子彈和敵機(jī)的集合
11.5 刪除己方飛機(jī)上的移動事件
11.6 回到游戲開始界面
一阶捆、html代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>javascript 原生打飛機(jī)游戲</title>
<link rel="stylesheet" href="style.css">
<script src="plane.js"></script>
</head>
<body>
<div id="game">
<div id="gameStart">
<span>開始游戲</span>
</div>
<div id="gameEnter">
<div id="myPlane">
<img src="image/my.gif" alt="">
</div>
<div id="bullets">
</div>
<div id="enemys"></div>
<div id="scores">
<p>得分:<span>0</span> 分</p>
</div>
</div>
</div>
</body>
</html>
二、css代碼
*{
margin: 0;
padding: 0;
}
#game{
width: 320px;
height: 568px;
margin: auto;
overflow: hidden;
}
#gameStart{
width: 100%;
height: 100%;
background: url(image/ks.png);
position: relative;
/*display: none;*/
}
#gameStart span{
width: 160px;
height: 40px;
display: block;
background: rgba(196,201,202);
border: 4px solid #666;
box-sizing: border-box;
text-align: center;
line-height: 32px;
font-size: 24px;
font-weight: bolder;
position: absolute;
left: 80px;
bottom: 200px;
cursor: pointer;
}
#gameStart span:hover{
color: #fff;
}
#gameEnter{
width: 100%;
height: 100%;
background: url(image/background_1.png);
position: relative;
display: none;
}
#myPlane{
width: 66px;
height: 80px;
position: absolute;
left: 127px;
bottom: 0;
cursor: pointer;
}
#myPlane{
width: 66px;
height: 80px;
}
#myPlane img{
cursor: move;
}
#bullets,#enemys{
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.b{
width: 6px;
height: 14px;
position: absolute;
}
.e{
position: absolute;
}
#scores{
width: 100%;
height: 40px;
line-height: 40px;
font-size: 24px;
font-weight: bolder;
padding: 0 20px;
}
#scores p{
text-align: right;
width: 80%;
}
三钦听、js代碼
;window.onload = function(){
// 獲取標(biāo)簽元素的方法
function $(idName){
return document.getElementById(idName);
}
// 獲取樣式使用最終值的函數(shù)
function getStyle(ele,attr){
var res = null;
if(ele.currentStyle){
res = ele.currentStyle[attr];
}else{
res = window.getComputedStyle(ele,null)[attr];
}
return parseFloat(res);
}
// 獲取需要使用到的標(biāo)簽元素
var game = $("game")
// 游戲開始的界面
, gameStart = $("gameStart")
// 進(jìn)入游戲的界面
, gameEnter = $("gameEnter")
, myPlane = $("myPlane")
, bulletsP = $("bullets")
, enemysP = $("enemys")
, s = $("scores").firstElementChild.firstElementChild;
// 獲取需要使用到的元素樣式
// 1洒试、獲取游戲界面的寬高
var gameW = getStyle(game,"width")
, gameH = getStyle(game,"height");
// 2、游戲界面的左上外邊距
var gameML = getStyle(game,"marginLeft")
, gameMT = getStyle(game,"marginTop");
// 3朴上、獲取己方飛機(jī)的寬高
var myPlaneW = getStyle(myPlane,"width")
, myPlaneH = getStyle(myPlane,"height");
// 4垒棋、子彈的寬高
var bulletW = 6
, bulletH = 14;
// 聲明需要使用到的全局變量
var gameStatus = false // 當(dāng)前的游戲狀態(tài)
, a = null // 創(chuàng)建子彈的定時(shí)器
, b = null // 創(chuàng)建敵機(jī)的定時(shí)器
, c = null // 背景圖運(yùn)動的定時(shí)器
, backgroundPY = 0 // 背景圖y軸的值
, bullets = [] // 所有子彈元素的集合
, enemys = [] // 所有敵機(jī)元素的集合
, scores = 0 // 得分
;
// 開始游戲
gameStart.firstElementChild.onclick = function(){
gameStart.style.display = "none";
gameEnter.style.display = "block";
// 給當(dāng)前的文檔添加鍵盤事件
document.onkeyup = function(evt){
var e = evt || window.event;
// 獲取到鍵盤的鍵值
var keyVal = e.keyCode;
if(keyVal == 32){
if(!gameStatus){
// 初始化得分
scores = 0;
// 開始游戲
this.onmousemove = myPlaneMove;
// 實(shí)現(xiàn)開始游戲之后背景圖的運(yùn)動
bgMove();
// 實(shí)現(xiàn)射擊
shot();
// 出現(xiàn)敵機(jī)
appearEnemy();
// 暫停游戲之后的開始游戲
// 子彈的繼續(xù)運(yùn)動
if(bullets.length != 0) reStart(bullets,1);
// 敵機(jī)的繼續(xù)運(yùn)動
if(enemys.length != 0) reStart(enemys);
}else{
// 暫停游戲
this.onmousemove = null;
// 清除創(chuàng)建敵機(jī)和創(chuàng)建子彈的定時(shí)器
clearInterval(a);
clearInterval(b);
clearInterval(c);
a = null;
b = null;
c = null;
// 清除所有子彈和所有敵機(jī)上的運(yùn)動定時(shí)器
clear(bullets);
clear(enemys);
}
gameStatus = !gameStatus;
}
}
}
// 己方飛機(jī)的移動
function myPlaneMove(evt){
var e = evt || window.event;
// 獲取鼠標(biāo)移動時(shí)的位置
var mouse_x = e.x || e.pageX
, mouse_y = e.y || e.pageY;
// 計(jì)算得到鼠標(biāo)移動時(shí)己方飛機(jī)的左上邊距
var last_myPlane_left = mouse_x - gameML - myPlaneW/2
, last_myPlane_top = mouse_y - gameMT - myPlaneH/2;
// 控制飛機(jī)不能脫離當(dāng)前的游戲界面
if(last_myPlane_left <= 0){
last_myPlane_left = 0;
}else if(last_myPlane_left >= gameW - myPlaneW){
last_myPlane_left = gameW - myPlaneW;
}
if(last_myPlane_top <= 0){
last_myPlane_top = 0;
}else if(last_myPlane_top >= gameH - myPlaneH){
last_myPlane_top = gameH - myPlaneH;
}
myPlane.style.left = last_myPlane_left + "px";
myPlane.style.top = last_myPlane_top + "px";
}
// 單位時(shí)間內(nèi)創(chuàng)建子彈
function shot(){
if(a) return ;
a = setInterval(function(){
// 創(chuàng)建子彈
createBullet();
},100);
}
// 制造子彈
function createBullet(){
var bullet = new Image();
bullet.src = "image/bullet1.png";
bullet.className = "b";
// 創(chuàng)建每一顆子彈都需要確定己方飛機(jī)的位置:
var myPlaneL = getStyle(myPlane,"left")
, myPlaneT = getStyle(myPlane,"top");
// 確定創(chuàng)建子彈的位置
var bulletL = myPlaneL + myPlaneW/2 - bulletW/2
, bulletT = myPlaneT - bulletH;
bullet.style.left = bulletL + "px";
bullet.style.top = bulletT + "px";
bulletsP.appendChild(bullet);
bullets.push(bullet);
move(bullet,"top");
}
// 子彈的運(yùn)動:運(yùn)動函數(shù)(勻速運(yùn)動)
function move(ele,attr){
var speed = -8;
ele.timer = setInterval(function(){
var moveVal = getStyle(ele,attr);
// 子彈運(yùn)動出游戲界面:清除子彈的定時(shí)器,刪除子彈元素
if(moveVal <= -bulletH){
clearInterval(ele.timer);
ele.parentNode.removeChild(ele);
bullets.splice(0,1);
}else{
ele.style[attr] = moveVal + speed + "px";
}
},10);
}
// 創(chuàng)建敵機(jī)數(shù)據(jù)對象
var enemysObj = {
enemy1: {
width: 34,
height: 24,
score: 100,
hp: 100
},
enemy2: {
width: 46,
height: 60,
score: 500,
hp: 800
},
enemy3: {
width: 110,
height: 164,
score: 1000,
hp: 2000
}
}
// 創(chuàng)建敵機(jī)的定時(shí)器
function appearEnemy(){
if(b) return ;
b = setInterval(function(){
// 制造敵機(jī)
createEnemy();
// 刪除死亡敵機(jī)
delEnemy();
},1000);
}
// 制造敵機(jī)的函數(shù)
function createEnemy(){
// 敵機(jī)出現(xiàn)概率的數(shù)據(jù)
var percentData = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,3];
// 敵機(jī)的類型
var enemyType = percentData[Math.floor(Math.random()*percentData.length)];
// 得到當(dāng)前隨機(jī)敵機(jī)的數(shù)據(jù)
var enemyData = enemysObj["enemy" + enemyType];
// 創(chuàng)建敵機(jī)所在的元素
var enemy = new Image(enemyData.width,enemyData.height);
enemy.src = "image/enemy" + enemyType + ".png";
enemy.t = enemyType;
enemy.score = enemyData.score;
enemy.hp = enemyData.hp;
enemy.className = "e";
enemy.dead = false; // 敵機(jī)存活
// 確定當(dāng)前敵機(jī)出現(xiàn)時(shí)的位置
var enemyL = Math.floor(Math.random()*(gameW - enemyData.width + 1))
, enemyT = -enemyData.height;
enemy.style.left = enemyL + "px";
enemy.style.top = enemyT + "px";
enemysP.appendChild(enemy);
enemys.push(enemy);
enemyMove(enemy,"top");
}
// 敵機(jī)的運(yùn)動
function enemyMove(ele,attr){
var speed = null;
if(ele.t == 1){
speed = 1.5;
}else if(ele.t == 2){
speed = 1;
}else if(ele.t == 3){
speed = 0.5;
}
ele.timer = setInterval(function(){
var moveVal = getStyle(ele,attr);
if(moveVal >= gameH){
clearInterval(ele.timer);
enemysP.removeChild(ele);
enemys.splice(0,1);
}else{
ele.style[attr] = moveVal + speed + "px";
// 每一架敵機(jī)運(yùn)動時(shí)痪宰,檢測和每一顆子彈的碰撞
danger(ele);
// 檢測碰撞
gameOver();
}
},10);
}
// 清除所有敵機(jī)和所有子彈上的運(yùn)動定時(shí)器
function clear(childs){
for(var i=0;i<childs.length;i++){
clearInterval(childs[i].timer);
}
}
// 暫停游戲之后的開始游戲
function reStart(childs,type){
for(var i=0;i<childs.length;i++){
type == 1 ? move(childs[i],"top") : enemyMove(childs[i],"top");
}
}
// 開始游戲之后的背景圖的運(yùn)動
function bgMove(){
c = setInterval(function(){
backgroundPY += 0.5;
if(backgroundPY >= gameH){
backgroundPY = 0;
}
gameEnter.style.backgroundPositionY = backgroundPY + "px";
},10);
}
// 檢測子彈和敵機(jī)的碰撞
function danger(enemy){
for(var i=0;i<bullets.length;i++){
// 得到子彈的左上邊距
var bulletL = getStyle(bullets[i],"left")
, bulletT = getStyle(bullets[i],"top");
// 得到敵機(jī)的左上邊距
var enemyL = getStyle(enemy,"left")
, enemyT = getStyle(enemy,"top");
// 得到敵機(jī)的寬高
var enemyW = getStyle(enemy,"width")
, enemyH = getStyle(enemy,"height");
var condition = bulletL + bulletW >= enemyL && bulletL <= enemyL + enemyW && bulletT <= enemyT + enemyH && bulletT + bulletH >= enemyT;
if(condition){
//子彈和敵機(jī)的碰撞:刪除子彈
// 1叼架、先清除碰撞子彈的定時(shí)器
clearInterval(bullets[i].timer);
// 2畔裕、刪除元素
bulletsP.removeChild(bullets[i]);
// 3、從集合中刪除子彈
bullets.splice(i,1);
// 4碉碉、子彈和敵機(jī)發(fā)生碰撞后柴钻,敵機(jī)血量減少淮韭,血量為0時(shí)垢粮,刪除敵機(jī)
enemy.hp -= 100;
if(enemy.hp == 0){
// 刪除敵機(jī)
clearInterval(enemy.timer);
// 替換爆炸圖片
enemy.src = "image/bz" + enemy.t + ".gif";
// 標(biāo)記死亡敵機(jī)
enemy.dead = true;
// 計(jì)算得分
scores += enemy.score;
s.innerHTML = scores;
}
}
}
}
// 在創(chuàng)建敵機(jī)時(shí),延時(shí)刪除掉集合和文檔中的死亡敵機(jī)
function delEnemy(){
for(var i=enemys.length - 1;i>=0;i--){
if(enemys[i].dead){
(function(index){
// 從文檔中刪除死亡敵機(jī)元素
enemysP.removeChild(enemys[index]);
// 從集合中刪除死亡敵機(jī)元素
enemys.splice(index,1);
})(i)
}
}
}
// 飛機(jī)碰撞靠粪,游戲結(jié)束
function gameOver(){
for(var i=0;i<enemys.length;i++){
if(!enemys[i].dead){ // 游戲機(jī)界面內(nèi)存活的敵機(jī)
// 檢測碰撞
// 1蜡吧、獲取敵機(jī)的左上邊距
var enemyL = getStyle(enemys[i],"left")
, enemyT = getStyle(enemys[i],"top");;
// 2、獲取敵機(jī)的寬高
var enemyW = getStyle(enemys[i],"width")
, enemyH = getStyle(enemys[i],"height");
// 3占键、獲取己方飛機(jī)的左上邊距
var myPlaneL = getStyle(myPlane,"left")
, myPlaneT = getStyle(myPlane,"top");
var condition = myPlaneL + myPlaneW >= enemyL && myPlaneL <= enemyL + enemyW && myPlaneT <= enemyT + enemyH && myPlaneT + myPlaneH >= enemyT;
if(condition){ // 己方飛機(jī)和敵機(jī)的碰撞
// console.log("碰撞了...");
// 清除定時(shí)器:創(chuàng)建子彈的定時(shí)器昔善、創(chuàng)建飛機(jī)的定時(shí)器、游戲背景圖的定時(shí)器
clearInterval(a);
clearInterval(b);
clearInterval(c);
a = null;
b = null;
c = null;
// 刪除子彈和敵機(jī)元素
remove(bullets);
remove(enemys);
// 集合清空
bullets = [];
enemys = [];
// 清除己方飛機(jī)的移動事件
document.onmousemove = null;
// 提示得分:
alert("Game over: " + scores + "分");
// 回到游戲開始界面
gameStart.style.display = "block";
gameEnter.style.display = "none";
myPlane.style.left = "127px";
myPlane.style.top = gameH - myPlaneH + "px";
}
}
}
}
// 刪除元素
function remove(childs){
for(var i = childs.length - 1;i>=0;i--){
clearInterval(childs[i].timer);
childs[i].parentNode.removeChild(childs[i]);
}
}
}
老規(guī)矩畔乙,附帶教學(xué)視頻:https://www.3mooc.com/front/couinfo/214