又到了每日分享时间了,今天分享的内容为:JavaScript打飞机小游戏
效果图:
实现逻辑:
第一步:实现页面的排版、布局
1.1 准备打飞机游戏需要使用到的图片
1.2 开始游戏界面
1.3 进入游戏的界面
1.3.1 己方飞机
1.3.2 敌方飞机
1.3.3 己方飞机发射的子弹
第二步:开始游戏
2.1 点击开始游戏按钮,进入到游戏界面
2.2 摁下空格键,实现己方飞机跟随鼠标的移动==》游戏的开始
2.3 第二次摁下空格键时,实现己方飞机的暂停移动==》游戏的暂停
2.4 以此类推,实现开始和暂停的交换
第三步:开始游戏之后的发射子弹
3.1 定时创建子弹:
3.1.1 单位时间内创建子弹的数量
3.1.2 开始游戏和暂停游戏时:暂停游戏后,不能再创建子弹;再次开始游戏时,不能存在多个创建子弹的定时器==》把上一次创建子弹的定时器给清除或者不再开启定时器
3.2 制造子弹
3.2.1 制造子弹时,确定子弹的位置
3.2.2 根据当前己方飞机的位置
3.2.3 把子弹追加到文档中去
3.3 子弹的运动
3.3.1 子弹的top值是-子弹的高度时,删除子弹,清除定时器
3.4 子弹消失
3.4.1 子弹飞出游戏界面
3.4.2 清除子弹==》每一颗飞出到游戏界面之外的子弹,肯定是第一个创建的子弹(当前子弹所在父元素下的第一个子元素)
第四步:开始游戏之后的创建敌机
4.1 定时创建敌机
4.1.1 单位时间内创建敌机的数量
4.1.2 暂停之后不能重复性的开启创建敌机的定时器
4.1.3 敌机的概率出现:大、中、小三种敌机
===》小:75% 中:20% 大:5%
4.2 制造敌机
4.3 敌机的运动
4.4 敌机的消失
第五步:实现游戏的暂停
5.1 敌机运动速度的控制
5.2 实现游戏的暂停
5.2.1 清除己方飞机的移动
5.2.2 清除创建敌机
5.2.3 清除创建子弹
5.2.4 清除每颗子弹上的运动
5.2.5 清除每架敌机上的运动
第六步:实现开始游戏之后的背景图的运动
6.1 改变的是背景图的background-position-y的值
6.2 游戏界面的高度568,每运动568px是一个循环
第七步:检测子弹和敌机的碰撞
7.1 每一个敌机都是运动的,每一颗子弹也是运动的==》在每一架敌机运动时,检测和所有游戏界面内存在的子弹的碰撞
7.2 创建全局变量:把当前游戏界面内存在的所有的子弹放入到该变量里
7.3 敌机运动的过程中,检测和每一颗子弹的碰撞
7.4 子弹和敌机发生碰撞时,子弹消失
7.4.1 把该子弹元素删除掉
7.4.2 把该子弹元素从全局变量集合里删除
7.5 敌机和子弹发生碰撞时,敌机血量减少==》每一颗子弹消耗的血量100
7.6 敌机的血量为0时,删除敌机元素???
第八步:实现敌机的爆炸效果
8.1 替换爆炸图片
8.2 区分存活的敌机和死亡敌机(爆炸过程中的敌机)==》标记每一架敌机的存活状态
8.3 延时删除敌机元素==》显示爆炸效果
8.4 在创建敌机时,删除敌机集合中的死亡敌机
第九步:实现游戏的得分
第十步:检测己方飞机和敌机的碰撞
10.1 一对多的关系:敌机运动,己方飞机运动
10.2 在每一架敌机运动的过程中检测
10.3 碰撞的原理
第十一步:游戏结束
11.1 清除掉当前页面上的所有的定时器
11.2 清除掉所有子弹上的定时器以及删除所有的子弹元素
11.3 清除掉素有敌机上的定时器以及删除所有的敌机元素
11.4 清空子弹和敌机的集合
11.5 删除己方飞机上的移动事件
11.6 回到游戏开始界面
一、html代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>javascript 原生打飞机游戏</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(){ // 获取标签元素的方法 function $(idName){ return document.getElementById(idName); } // 获取样式使用最终值的函数 function getStyle(ele,attr){ var res = null; if(ele.currentStyle){ res = ele.currentStyle[attr]; }else{ res = window.getComputedStyle(ele,null)[attr]; } return parseFloat(res); } // 获取需要使用到的标签元素 var game = $("game") // 游戏开始的界面 , gameStart = $("gameStart") // 进入游戏的界面 , 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、获取己方飞机的宽高 var myPlaneW = getStyle(myPlane,"width") , myPlaneH = getStyle(myPlane,"height"); // 4、子弹的宽高 var bulletW = 6 , bulletH = 14; // 声明需要使用到的全局变量 var gameStatus = false // 当前的游戏状态 , a = null // 创建子弹的定时器 , b = null // 创建敌机的定时器 , c = null // 背景图运动的定时器 , backgroundPY = 0 // 背景图y轴的值 , bullets = [] // 所有子弹元素的集合 , enemys = [] // 所有敌机元素的集合 , scores = 0 // 得分 ; // 开始游戏 gameStart.firstElementChild.onclick = function(){ gameStart.style.display = "none"; gameEnter.style.display = "block"; // 给当前的文档添加键盘事件 document.onkeyup = function(evt){ var e = evt || window.event; // 获取到键盘的键值 var keyVal = e.keyCode; if(keyVal == 32){ if(!gameStatus){ // 初始化得分 scores = 0; // 开始游戏 this.onmousemove = myPlaneMove; // 实现开始游戏之后背景图的运动 bgMove(); // 实现射击 shot(); // 出现敌机 appearEnemy(); // 暂停游戏之后的开始游戏 // 子弹的继续运动 if(bullets.length != 0) reStart(bullets,1); // 敌机的继续运动 if(enemys.length != 0) reStart(enemys); }else{ // 暂停游戏 this.onmousemove = null; // 清除创建敌机和创建子弹的定时器 clearInterval(a); clearInterval(b); clearInterval(c); a = null; b = null; c = null; // 清除所有子弹和所有敌机上的运动定时器 clear(bullets); clear(enemys); } gameStatus = !gameStatus; } } } // 己方飞机的移动 function myPlaneMove(evt){ var e = evt || window.event; // 获取鼠标移动时的位置 var mouse_x = e.x || e.pageX , mouse_y = e.y || e.pageY; // 计算得到鼠标移动时己方飞机的左上边距 var last_myPlane_left = mouse_x - gameML - myPlaneW/2 , last_myPlane_top = mouse_y - gameMT - myPlaneH/2; // 控制飞机不能脱离当前的游戏界面 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"; } // 单位时间内创建子弹 function shot(){ if(a) return ; a = setInterval(function(){ // 创建子弹 createBullet(); },100); } // 制造子弹 function createBullet(){ var bullet = new Image(); bullet.src = "image/bullet1.png"; bullet.className = "b"; // 创建每一颗子弹都需要确定己方飞机的位置: var myPlaneL = getStyle(myPlane,"left") , myPlaneT = getStyle(myPlane,"top"); // 确定创建子弹的位置 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"); } // 子弹的运动:运动函数(匀速运动) function move(ele,attr){ var speed = -8; ele.timer = setInterval(function(){ var moveVal = getStyle(ele,attr); // 子弹运动出游戏界面:清除子弹的定时器,删除子弹元素 if(moveVal <= -bulletH){ clearInterval(ele.timer); ele.parentNode.removeChild(ele); bullets.splice(0,1); }else{ ele.style[attr] = moveVal + speed + "px"; } },10); } // 创建敌机数据对象 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 } } // 创建敌机的定时器 function appearEnemy(){ if(b) return ; b = setInterval(function(){ // 制造敌机 createEnemy(); // 删除死亡敌机 delEnemy(); },1000); } // 制造敌机的函数 function createEnemy(){ // 敌机出现概率的数据 var percentData = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,3]; // 敌机的类型 var enemyType = percentData[Math.floor(Math.random()*percentData.length)]; // 得到当前随机敌机的数据 var enemyData = enemysObj["enemy" + enemyType]; // 创建敌机所在的元素 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; // 敌机存活 // 确定当前敌机出现时的位置 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"); } // 敌机的运动 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"; // 每一架敌机运动时,检测和每一颗子弹的碰撞 danger(ele); // 检测碰撞 gameOver(); } },10); } // 清除所有敌机和所有子弹上的运动定时器 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"); } } // 开始游戏之后的背景图的运动 function bgMove(){ c = setInterval(function(){ backgroundPY += 0.5; if(backgroundPY >= gameH){ backgroundPY = 0; } gameEnter.style.backgroundPositionY = backgroundPY + "px"; },10); } // 检测子弹和敌机的碰撞 function danger(enemy){ for(var i=0;i<bullets.length;i++){ // 得到子弹的左上边距 var bulletL = getStyle(bullets[i],"left") , bulletT = getStyle(bullets[i],"top"); // 得到敌机的左上边距 var enemyL = getStyle(enemy,"left") , enemyT = getStyle(enemy,"top"); // 得到敌机的宽高 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){ //子弹和敌机的碰撞:删除子弹 // 1、先清除碰撞子弹的定时器 clearInterval(bullets[i].timer); // 2、删除元素 bulletsP.removeChild(bullets[i]); // 3、从集合中删除子弹 bullets.splice(i,1); // 4、子弹和敌机发生碰撞后,敌机血量减少,血量为0时,删除敌机 enemy.hp -= 100; if(enemy.hp == 0){ // 删除敌机 clearInterval(enemy.timer); // 替换爆炸图片 enemy.src = "image/bz" + enemy.t + ".gif"; // 标记死亡敌机 enemy.dead = true; // 计算得分 scores += enemy.score; s.innerHTML = scores; } } } } // 在创建敌机时,延时删除掉集合和文档中的死亡敌机 function delEnemy(){ for(var i=enemys.length - 1;i>=0;i--){ if(enemys[i].dead){ (function(index){ // 从文档中删除死亡敌机元素 enemysP.removeChild(enemys[index]); // 从集合中删除死亡敌机元素 enemys.splice(index,1); })(i) } } } // 飞机碰撞,游戏结束 function gameOver(){ for(var i=0;i<enemys.length;i++){ if(!enemys[i].dead){ // 游戏机界面内存活的敌机 // 检测碰撞 // 1、获取敌机的左上边距 var enemyL = getStyle(enemys[i],"left") , enemyT = getStyle(enemys[i],"top");; // 2、获取敌机的宽高 var enemyW = getStyle(enemys[i],"width") , enemyH = getStyle(enemys[i],"height"); // 3、获取己方飞机的左上边距 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){ // 己方飞机和敌机的碰撞 // console.log("碰撞了..."); // 清除定时器:创建子弹的定时器、创建飞机的定时器、游戏背景图的定时器 clearInterval(a); clearInterval(b); clearInterval(c); a = null; b = null; c = null; // 删除子弹和敌机元素 remove(bullets); remove(enemys); // 集合清空 bullets = []; enemys = []; // 清除己方飞机的移动事件 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]); } } }
老规矩,附带教学视频:https://www.3mooc.com/front/couinfo/214