星际飞机大战游戏
在github里看到了个不错的脚本游戏,决定亲自动手来写
然后在四天的琢磨下总算是把飞机游戏给写出来了,效果如下
满足大家的需求 先给源代码 下面有详细的思路分享
源代码:
先创建一个文件夹 在这个文件夹里面创建 images文件夹 和 js 文件夹 和一个index.html 如图
因为代码里绑定了相对路径 如果不这么做显示不出来
images里面的素材可以自己找 但是图片名字一定要跟下面的一样
bak背景 enemy敌人飞机 hero我方飞机 newbullet子弹 pause暂停
js文件夹存放下面两个文件
文件名:elements.js (记得把win7默认隐藏后缀的勾去掉)
代码:
function bullet(x,y){ this.x=x; this.y=y; this.islive=true; this.timmer=null; this.run=function run(){ if(this.y<-10||this.islive==false){ clearInterval(this.timmer); this.islive=false; }else{ this.y-=20; } } } function enemy(x,y){ this.x=x; this.y=y; this.islive=true; this.timmer=null; this.run=function run(){ if(this.y>boxheight||this.islive==false){ clearInterval(this.timmer); this.islive=false; }else{ this.y+=2.5; } } }
文件名:myplane.js (记得把隐藏后缀去掉)
代码:
var sp; var fps=55; var score=0; var boxx=0; var boxy=0; var boxwidth=500; var boxheight=500; var planeImage; var planex; var planey; var planewidth=60; var planeheight=60; var bulletImage; var herobullet; var allbullets = new Array(); var bulletwidth=10; var bulletheight=10; var enemyImage; var heroenemy; var allenemys = new Array(); var enemywidth=30; var enemyheight=30; var gameTimmer; var btimmer; var etimmer; bulletImage = new Image(); bulletImage.src="images/newbullet.PNG"; enemyImage = new Image() enemyImage.src="images/enemy.jpg"; function beginplane(){ planex = boxwidth / 2 - planewidth /2 ; planey = boxheight - planeheight; planeImage = new Image(); planeImage.src="images/hero.jpg"; } function init(){ canvas = document.getElementById(‘canvas‘); cxt = canvas.getContext(‘2d‘); cxt.lineWidth=3; beginplane(); var body = document.getElementsByTagName(‘body‘)[0]; btimmer = setInterval(producebullet,500); etimmer = setInterval(produceenemy,800) body.addEventListener(‘keydown‘,function (event){ switch(event.keyCode){ case 37 : if(planex>boxx){sp=8}else{sp=0}planex-=sp;break; case 38 : if(planey>boxy){sp=8}else{sp=0}planey-=sp;break; case 39 : if((planex+planewidth)<boxwidth){sp=8}else{sp=0}planex+=sp;break; case 40 : if((planey+planeheight)<boxheight){sp=8}else{sp=0}planey+=sp;break; default:break; } },false) gameTimmer = setInterval(run,1000/fps); } function drawenemy(){ for (var i=0;i<allenemys.length;i++){ if(allenemys[i].islive){ cxt.drawImage(enemyImage,allenemys[i].x,allenemys[i].y,enemywidth,enemyheight); } } } function drawplane(){ cxt.clearRect(boxx,boxy,boxwidth,boxheight); cxt.drawImage(planeImage,planex,planey,planewidth,planeheight); } function drawbullet(){ for(var i=0;i<allbullets.length;i++){ if(allbullets[i].islive){ cxt.drawImage(bulletImage,allbullets[i].x,allbullets[i].y,bulletwidth,bulletheight); } } } function produceenemy(){ var x = Math.ceil(Math.random()*(boxwidth-planeheight)); heroenemy = new enemy(x,33); allenemys.push(heroenemy); var timmer = setInterval("allenemys["+ (allenemys.length-1) + "].run()",50); allenemys[allenemys.length-1].timmer=timmer; } function producebullet(){ herobullet = new bullet(planex+planewidth/2,planey+10); allbullets.push(herobullet); var timmer = setInterval("allbullets[" + (allbullets.length-1) + "].run()",50); allbullets[(allbullets.length-1)].timmer=timmer; } function checkbullet(){ for(var i=0;i<allenemys.length;i++){ if(allenemys[i].islive){ var e =allenemys[i]; for(var j=0;j<allbullets.length;j++){ if(allbullets[j].islive){ var b = allbullets[j]; if(b.x>e.x-bulletwidth&&b.x+bulletwidth<e.x+enemywidth+10&&b.y<e.y){ e.islive=false; b.islive=false; score+=100; } } } } } } function checkplane(){ for(var i=0;i<allenemys.length;i++){ if(allenemys[i].islive){ var e = allenemys[i]; if(e.x+enemywidth>planex&&e.x<planex+planewidth&&e.y>planey||e.y>boxheight){ e.islive=false; stop(); score=0; } } } } function drawscore(){ document.getElementById(‘score‘).innerHTML=score; } function run(){ drawplane(); drawbullet(); drawscore(); drawenemy(); checkbullet(); checkplane(); }
var sp; var fps=55; var score=0; var boxx=0; var boxy=0; var boxwidth=500; var boxheight=500; var planeImage; var planex; var planey; var planewidth=60; var planeheight=60; var bulletImage; var herobullet; var allbullets = new Array(); var bulletwidth=10; var bulletheight=10; var enemyImage; var heroenemy; var allenemys = new Array(); var enemywidth=30; var enemyheight=30; var gameTimmer; var btimmer; var etimmer; bulletImage = new Image(); bulletImage.src="images/newbullet.PNG"; enemyImage = new Image() enemyImage.src="images/enemy.jpg"; function beginplane(){ planex = boxwidth / 2 - planewidth /2 ; planey = boxheight - planeheight; planeImage = new Image(); planeImage.src="images/hero.jpg"; } function init(){ canvas = document.getElementById(‘canvas‘); cxt = canvas.getContext(‘2d‘); cxt.lineWidth=3; beginplane(); var body = document.getElementsByTagName(‘body‘)[0]; btimmer = setInterval(producebullet,500); etimmer = setInterval(produceenemy,800) body.addEventListener(‘keydown‘,function (event){ switch(event.keyCode){ case 37 : if(planex>boxx){sp=8}else{sp=0}planex-=sp;break; case 38 : if(planey>boxy){sp=8}else{sp=0}planey-=sp;break; case 39 : if((planex+planewidth)<boxwidth){sp=8}else{sp=0}planex+=sp;break; case 40 : if((planey+planeheight)<boxheight){sp=8}else{sp=0}planey+=sp;break; default:break; } },false) gameTimmer = setInterval(run,1000/fps); } function drawenemy(){ for (var i=0;i<allenemys.length;i++){ if(allenemys[i].islive){ cxt.drawImage(enemyImage,allenemys[i].x,allenemys[i].y,enemywidth,enemyheight); } } } function drawplane(){ cxt.clearRect(boxx,boxy,boxwidth,boxheight); cxt.drawImage(planeImage,planex,planey,planewidth,planeheight); } function drawbullet(){ for(var i=0;i<allbullets.length;i++){ if(allbullets[i].islive){ cxt.drawImage(bulletImage,allbullets[i].x,allbullets[i].y,bulletwidth,bulletheight); } } } function produceenemy(){ var x = Math.ceil(Math.random()*(boxwidth-planeheight)); heroenemy = new enemy(x,33); allenemys.push(heroenemy); var timmer = setInterval("allenemys["+ (allenemys.length-1) + "].run()",50); allenemys[allenemys.length-1].timmer=timmer; } function producebullet(){ herobullet = new bullet(planex+planewidth/2,planey+10); allbullets.push(herobullet); var timmer = setInterval("allbullets[" + (allbullets.length-1) + "].run()",50); allbullets[(allbullets.length-1)].timmer=timmer; } function checkbullet(){ for(var i=0;i<allenemys.length;i++){ if(allenemys[i].islive){ var e =allenemys[i]; for(var j=0;j<allbullets.length;j++){ if(allbullets[j].islive){ var b = allbullets[j]; if(b.x>e.x-bulletwidth&&b.x+bulletwidth<e.x+enemywidth+10&&b.y<e.y){ e.islive=false; b.islive=false; score+=100; } } } } } } function checkplane(){ for(var i=0;i<allenemys.length;i++){ if(allenemys[i].islive){ var e = allenemys[i]; if(e.x+enemywidth>planex&&e.x<planex+planewidth&&e.y>planey||e.y>boxheight){ e.islive=false; stop(); score=0; } } } } function drawscore(){ document.getElementById(‘score‘).innerHTML=score; } function run(){ drawplane(); drawbullet(); drawscore(); drawenemy(); checkbullet(); checkplane(); }
还有文件名:myplane.html 记得这个是要放在js文件外面的 然后编辑他输入下面代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body style=" padding: 0px; color: rgb(0, 0, 255); line-height: 1.5 !important;">> <canvas id="canvas" width="500" height="500" style="background-image: url(images/bak.PNG);"></canvas> <img src="images/pause.PNG" style="position: absolute;top: 20px;left: 30px;" onclick="stop()"/> <div style="position: absolute;top: 90px;left: 30px;font-weight: bold;font-size: 40px;color:cornflowerblue"><span id="score">0</span></div> <input style="position: absolute;top:350px;left: 230px;" type="button" value="start" id="start" onclick="init();startHide()" /> <div style="position: absolute;top: 200px;left: 180px;"><span id="rules">击中敌机得分<br>飞机撞机或敌机落地游戏结束</span></div> <script type="text/javascript" src="js/elements.js"></script> <script type="text/javascript" src="js/myplane.js" ></script> <script> var rules = document.getElementById(‘rules‘); var showScore = document.getElementById(‘showScore‘); var start = document.getElementById(‘start‘); function startHide(){ rules.style.display="none"; start.style.display="none"; } function stop(){ clearInterval(gameTimmer); clearInterval(btimmer); clearInterval(etimmer); cxt.clearRect(boxx,boxy,boxwidth,boxheight); allenemys.length=0; allbullets.length=0; rules.style.display=""; start.style.display=""; } </script> </body> </html>
然后就可以玩了
如果有疑问可以提出
如果你想有收获 那么就耐心往下看把
下面和大家分享下飞机游戏的制作 过程虽然有点痛苦 但这真的很好玩 比如把飞机该无敌 超级子弹 并发子弹 等等
另外 建议大家先看完再去做 边看边做也可以 但心里应该有一个整体的思路
要把整个代码吃下确实不容易,但吃下后受益匪浅
如果你能够沉下心来 一样也可以做出 因此稍安勿躁
废话不多说 下面说思路
不过在此先先说好 下面的代码 只是临时打出来的 并没有去真实的去测试过 可能会存在语法错误 逻辑错误等等
希望各位能够指出不足的地方 或者谅解错误 毕竟我想分享的思路而不是代码 代码上面有
做游戏的第一件最简单的事情,就是准备素材----当然也可以放到最后来做,这样的话你需要找简单替代物先代替之
元素有:背景(可不要) 敌机 我机(下面就叫飞机) 子弹 还有暂停图标
素材的大小是游戏的关键 可以利用javascript的画布中drawImage()来改变其大小
那么现在来开始做游戏
首先搞个画布出来
<canvas id="canvas" width=500 height=500 style="border:1px solid #c3c3c3"></canvas>
有了画布就可以先把我们的主角 飞机画上去:
//获取画布
canvas = document.getElementById(‘canvas‘) cxt = canvas.getContext(‘2d‘);
//设置画布属性:横坐标 纵坐标 宽高
var boxx=0 var boxy=0 var boxwidth=500 var boxheight=500
//设置飞机属性 :横坐标 纵坐标 宽高
var planex; var planey; var planewidth=60; var planeheight=60; var planeImage = new Image(); planeImage.src="images/hero.jpg";
主角飞机的开始位置按常规套路出牌的话 横坐标就是画布中间 纵坐标就是画布底端
planex = (boxwidth - planewidth) / 2 planey = boxheight - planeheight
注意 飞机的坐标(x,y)指的是飞机图片的最左上角的那个坐标,因此在上面还需要算上飞机的长度
//有了四大神器:横 纵 宽 高 就可以把飞机画出来了
cxt.drawImage(planeImage,planex,planey,planewidth,planeheight);
飞机画出来了但是飞机不会动 那么怎么能让飞机动呢? 改变其坐标! 那么什么时候动呢? 按下键盘上的 ↑ ↓ ← → 键的时候
我们知道键盘有个事件驱动 onkeydown 而这个事件驱动有个属性keycode 用这个属性可以绑定上下左右键对应的函数
左 : 37
上 : 38
右 : 39
下 : 40
而且游戏开始 我们当然期望我们所按下的按键能 够实时的得到响应 而javascript提供了个很好的接口可以实时的响应事件:
addEventListener()函数
语法
element.addEventListener(event, function, useCapture)
这个函数可以用来实时监听事件 使得我们的按下按键可以得到响应
那么可以飞机能动就不是啥问题了!
首先声明个飞机运动跨度的变量
var sp=0;
然后监听body元素 以及临界判断 否则你飞机要飞出界!
body.addEventListener(‘keydown‘,function (event){ switch(event.keyCode){ case 37 : if(planex>boxx){sp=8}else{sp=0}planex-=sp;break; case 38 : if(planey>boxy){sp=8}else{sp=0}planey-=sp;break; case 39 : if((planex+planewidth)<boxwidth){sp=8}else{sp=0}planex+=sp;break; case 40 : if((planey+planeheight)<boxheight){sp=8}else{sp=0}planey+=sp;break; default:break; } },false)
到这里你的飞机已经可以动了 但是你激动的去测试一下 发现飞机没动!!
原因是这里只是飞机的坐标改变了 但是飞机的图片还在原地啊 ,因此需要一个计时器
每隔一段时间重新把飞机重画一次 这样飞机真的可以动了
function drawplane(){ cxt.clearRect(boxx,boxy,boxwidth,boxheight); cxt.drawImage(planeImage,planex,planey,planewidth,planeheight); } var fps //用来调画面流畅感 玩过LOL的不可能不知道fps是啥吧 var gameTimmer = setInterval (run,1000/fps); //gameTimer游戏的总驱动的计时器 function run(){ //游戏及驱动 drawplane(); }
光有飞机还不够 还需要子弹 那么现在开始画子弹
老规矩先来设置子弹的属性
var bulletx; var bullety; var bulletwidth=10; var bulletheight=10; var bulletImage=new Image(); bulletImage.src="images/bullet.png"
另外我们需要一个数组用来存放所有的子弹
再用一个变量来表示每一个子弹
var herobullet; var allbullets = new Array();
然后对子弹的特点分析下:首先每颗子弹的起始位置应该是飞机的中间偏下
bulletx=planex+planewidth/2 bullety=planey+bulletheight
然后每颗子弹都应该会动,除非他出界或者击中了敌机,因此可以写个子弹的构造函数
function bullet(x,y){ this.x=x; this.y=y; this.islive=true; //用于判断子弹是否存活 this.timmer=null; //子弹计时器 this.run = function run(){ if(this.islive==false||this.y<-10){ clearInterval(this.timmer); this.islive=false; }else{ this.y-=20 //让子弹往上飞 } } }
有了做子弹的秘方 那么就可以开始制造子弹了
function producebullet(){ herobullet = new bullet(bulletx,bullety); allbullets.push(herobullet); var timmer = setInterval("allbullets[" + (allbullets.length-1) +"].run()" , 50); allbullets[allbullets.length-1].timmer=timmer; }
同样上面改变的仅仅是子弹的坐标 还需要改变下子弹的图片
function drawbullet(){ for (var i=0;i<allbullets.length;i++){ if(allbullets[i].islive){ cxt.drawImage(bulletImage,allbullets.x,allbullets.y,bulletwidth,bulletheight); } } }
然后把drawbullet函数 放到之前定义的run函数里 不是子弹的方法
function run(){ drawplane(); drawbullet(); }
这样子弹就可以被实时的画出来了
然后给生产子弹以和动态改变子弹坐标的函数 producebullet 加个计时器
btimmer = setInterval(producebullet,500)
这样子弹就可以自动生产 以及自动改变自己的坐标了
这时候可以测试下是否能够自动产生子弹
按照上面的方法 画出敌机也是一个方法
设置属性 -> 确定坐标 -> 构造函数 -> 画出敌机 -> 计时器
但是这里有个不同的点 那就是敌机初始的横坐标应该是随机的 而纵坐标都是0 (顶部位置)
说到随机 就能想到: Math.random()函数 但这个只能产生0~1的随机数
因此 Math.random*500 范围就是0~500范围
最后四拾伍入 Math.ceil(Math.random*500);
画敌机的方法和画子弹的方法是一样的 因此这里简单的带过
//构造函数 function enemy(x,y){ this.x=x; this.y=y; this.islive=true; this.timmer=null; this.run = function run(){ if (this.islive==false||this.y>boxheight){ clearInterval(this.timmer); this.islive=false; }else{ this.y+=2.5; } } } //生产敌机 function produceenemy(){ enemyx=Math.ceil(Math.random()*500); enemyy=33; heroenemy = new enemy(enemyx,enemyy); allenemys.push(heroenemy); var timmer = setInterval("allenemys[" + (allenemys.length-1) + "].run()"); allenemys[allenemys.length-1].timmer=timmer; } //画出敌机 function drawenemy(){ for (var i=0;i<allenemys.length;i++){ if(allenemys[i].islive){ cxt.drawImage(enemyImage,allenemys[i].x,allenemys[i].y,enemywidth,enemyheight) } } }
最后把 drawenemy 加入run函数里 给produeenemy 加个计时器
function run(){ drawplane(); drawbullet(); drawenemy(); }
etimmer = setInterval(produceenemy,800);
飞机 敌机 子弹 都画好了 而且都可以动起来了 , 现在来写子弹碰到敌机时敌机消失的规则
上图可以清晰的看出子弹击中敌机的范围
击中条件:
bulletx + bulletwidth > enemyx
bulletx < enemyx + enemywidth
bullety < enemyy + enemyheight
function checkbullet{ for(var i=0;i<allenemys.length;i++){ if (allenemys[i].islive){ var e = allenemys[i]; } for(var j=0;j<allbullets.length;j++){ if(allbullets[j].islive){ var b = allbullets[j]; if(b.x+b.width>e.x&&b.x<e.x+e.width&&b.y<e.y+e.height){ b.islive=false; e.islive=false; score+=100; //加分规则 等等说 } } } } }
我机的死亡的规则:
击中条件:
enemyx+enemywidth > planex
enemyx < planex + planewidth
enemyy + enemyheight > planey
function checkenemy(){ for(var i=0;i<allenemys[i].length;i++){ if(allenemys[i].islive){ var e = allenemys[i]; if(e.x+e.width > planex && e.x < planex + planewidth && e.y + e.height > planey){ e.islive=false; stop(); } } } }
然后随便把stop函数写出来
function stop(){ clearInterval(btimmer); //停止生产子弹 clearInterval(etimmer); //停止生产敌机 clearInterval(gameTimmer); //停止游戏 allenemys.length=0; //初始化 allbullets.length=0; //初始化 show.innerHTML=score; //统计总分 等等说 score=0; }
然后把checkbullet函数 和checkenemy函数 放到游戏驱动run 里头
function run(){ drawplane(); drawenemy(); drawbullet(); checkbullet(); checkenemy(); drawscore(); //实时加分 现在说 }
基本上游戏就大功告成了 不过为了更完美些 来个加分规则
首先创建个放分数位置的标签
<div style="position: absolute;top: 90px;left: 30px;font-weight: bold;font-size: 40px;color:cornflowerblue"> <span id="show">0</span></div>
获取标签
show = document.getElementById(‘show‘);
实时计分
function drawscore(){ show.innerHTML=score; }
当然还可以加一些小细节,比如暂停按钮 弹出窗口统计得分
还可以玩好玩的,比如飞机无敌 无限子弹 超级子弹 无敌并排子弹 总之你自己想怎么改都行