用javascript写星际飞机大战游戏

时间:2022-01-21 13:42:42

在github里看到了个不错的脚本游戏,决定亲自动手来写,效果如下

用javascript写星际飞机大战游戏

 

下面是代码的思路分享

把整个代码理解消化确实不容易,但是如果你坚持看完相信你一定会有收获

如果没兴趣可以直接点击下面的链接 复制代码 开玩:

http://www.cnblogs.com/demonxian3/p/6241755.html

 

1丶首先准备好素材

游戏的元素有:飞机 敌机 子弹 背景 暂停

 

用javascript写星际飞机大战游戏

 

素材的大小可以通过drawImage()来改变其大小,因此不需要太纠结素材多少像素

 

创建一个html文件 和一个js文件

然后开始编辑该html文件

 

2.写一个画布:

<canvas id="canvas" width=500 height=500 style="border:1px solid #c3c3c3"></canvas>

 

 

3.获取画布对象

canvas = document.getElementById('canvas') 

cxt
= canvas.getContext('2d');

 

 

4.设置画布属性

var boxx=0

var boxy=0

var boxwidth=500

var boxheight=500

 

 

 

 **************************画飞机****************************

 

5.声明飞机相关的变量

飞机横坐标 纵坐标 宽度 高度 这些都是为下面的drawImage做准备的

var planex;

var planey;

var planewidth=60;

var planeheight=60;

var planeImage = new Image();

planeImage.src
="images/hero.jpg"; //引入图片

 

6.布置飞机初始位置

planex = (boxwidth - planewidth) / 2 //画布的*

planey
= boxheight - planeheight     //画布的底端

因为这里的坐标(x,y)指的是飞机左上角的坐标,因此需要把飞机的长度算上

 

 

7.画出飞机

有了坐标和宽高就可以把飞机画出来了

cxt.drawImage(planeImage,planex,planey,planewidth,planeheight);

 

现在可以打开网页测试下,看看飞机是否画出来了,

如果没有画出来,那么请别灰心,耐心的查一下有什么错误的地方

如果成功显示出飞机了那么go on!

 

 

飞机画出来了但是飞机不会动 

那么怎么能让飞机动呢? 

改变其坐标!

那么什么时候动呢?

按下键盘上的 ↑ ↓ ← → 键的时候

我们知道键盘有个事件驱动 onkeydown

而这个事件驱动有个属性keycode 

用这个属性可以绑定上下左右键对应的函数

如下可以看到对应的keycode码

用javascript写星际飞机大战游戏

 

下面是四个我们需要的按键的对应码

左 : 37

上 : 38

右 : 39

下 : 40

 

光有事件驱动onkeydown还不够,我们还需要实时监听事件的发生

说的通俗点就是 你在任意时刻去按键盘 程序都能够及时响应

下面这个函数就可以帮我们实时监听事件

addEventListener()函数

语法

element.addEventListener(event, function, useCapture) 参数解释:element    表示需要使用该方法的对象  event        表示监听什么事件   function    表示监听到事件后做出什么响应  useCapture 表示在捕获或冒泡执行 默认为false 我们就按照默认来  声明一个运动跨度变量 这个变量的作用你马上就能看到了
var sp=0;

 

 8.监听body元素 响应事件
 下面四个if语句用来判断飞机是否出界 
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)

 

到这里 你可以测试一下飞机是否可以动起来了

当然我会直接告诉你结果----不能动!!

因为上面的事件监听改变的只是飞机的坐标,但是图片还在原地

为了让图片跟着坐标动起来,我们需要写一个函数

 

 

9.更新飞机图片位置函数

function drawplane(){

cxt.clearRect(boxx,boxy,boxwidth,boxheight); //清除所有就元素

cxt.drawImage(planeImage,planex,planey,planewidth,planeheight);  //重新画出飞机

}


var fps                          //其实只是用来调飞机流畅度

var gameTimmer = setInterval (run,1000/fps);     //gameTimer是游戏的总驱动计时器



function run(){                    //drawplane函数自动运行

drawplane();                      

}

 

 **************************画子弹****************************

 

 10.设置子弹的相关变量 也是为drawImage函数的五个参数所做准备

var bulletx;

var bullety;

var bulletwidth=10;

var bulletheight=10;

var bulletImage=new Image();

bulletImage.src
="images/bullet.png"

 

 

11.存放子弹的弹夹-----数组

用数组来存放子弹方便我们访问每个子弹对象

var herobullet; //用来表示单个子弹

var allbullets = new Array(); //用来表示所有子弹

 

12.设置子弹初始位置

我们希望 每颗子弹的起始位置是随着飞机而改变的 因此把飞机的变量引进来

bulletx=planex+planewidth/2

bullety
=planey+bulletheight

 

13.声明子弹的构造函数、

这部分有点难理解 也是本代码的难点

下面声明的构造函数是用来制作子弹的

 

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       //让子弹往上飞

   }

}

}

 

 14.生产子弹

 有了做子弹的秘方 那么就可以开始制造子弹了

 在这里可以使用到我们之前定义的数组存放每颗子弹

function producebullet(){

herobullet
= new bullet(bulletx,bullety); //生产子弹

allbullets.push(herobullet); //存放子弹

var timmer = setInterval("allbullets[" + (allbullets.length-1) +"].run()" , 50); //设置子弹子弹运行 这里用到eval可以将字符变为有效方法

allbullets[allbullets.length
-1].timmer=timmer; //将自动运行的子弹方法赋予到子弹的属性

}

 

15.画出子弹

同飞机的道理相同:光改变坐标是看不出效果,还需要把图片位置也更新了

function drawbullet(){

for (var i=0;i<allbullets.length;i++){ //遍历每颗子弹

if(allbullets[i].islive){ //如果子弹挂了 就不需要再画出来了

cxt.drawImage(bulletImage,allbullets.x,allbullets.y,bulletwidth,bulletheight);

}

}

}

 

 16.让drawbullet函数自动运行

然后把drawbullet函数 放到之前定义的run函数里 不是子弹的方法

function run(){

drawplane();

drawbullet();

}

 

17.让子弹自动生产

给生产子弹的函数加个计时器

btimmer = setInterval(producebullet,500)

 

 **************************画敌机****************************

我们来回顾下画子弹的步骤

 

设置相关属性 ->  确定初始坐标 -> 子弹构造函数 ->  生产子弹 -> 画出子弹 -> 自动生产和绘画

 

画敌机的步骤和上面的步骤是一样的

 

但是有个不同的点 那就是敌机初始的横坐标应该是随机的  而纵坐标都是0 (顶部位置)

 

说到随机 Math.random()函数 是不可以缺少的

但这个只能产生0~1的随机数

因此 Math.random*500   范围就是0~500范围

最后四拾伍入   Math.ceil(Math.random*500);

 

18.设置敌机的相关属性

 

var enemyx;
var enemyy;
var enemywidth=30
var enemyheight=30
var allenemys = new Arr(); //和子弹一样 数组用来存放所有敌机
var heroenemy; //用来表示其中单个敌机
var enemyImage= new Image();
enemyImage.src
="images/enemy.png"

 

 

19.敌机构造函数

 

//构造函数
//下面基本上和子弹差不多 就不解释了
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;

}

}

}

20生产敌机

 

//生产随机位置的敌机

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()"); //启动run函数并使其自动运行

allenemys[allenemys.length
-1].timmer=timmer; //run函数赋予在enemy属性

}

 

21画出敌机

//画出敌机

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)

}

}

}

 

 

22自动生产敌机 更新敌机

最后把 drawenemy 加入run函数里  给produeenemy 加个计时器

function run(){

drawplane();

drawbullet();

drawenemy();

}

etimmer = setInterval(produceenemy,800);

 

 **************************击中敌机****************************

飞机 敌机  子弹 都画好了 而且都可以动起来了 , 现在来写子弹碰到敌机时敌机消失的规则

用javascript写星际飞机大战游戏

 

上图可以清晰的看出子弹击中敌机的范围

击中条件:

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; //在构造函数里只要islive的属性为假 就会停止run函数的计时器

          e.islive
=false; //因此子弹和敌机相关计时器都被clear掉了

          score
+=100; //加分

        }

      }

    }

  }

}

 

**************************击中我机****************************

我机的死亡的规则:

 

用javascript写星际飞机大战游戏

 

击中条件:

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;

}

 

 

当然还可以加一些小细节,比如暂停按钮 弹出窗口统计得分

还可以玩好玩的,比如飞机无敌 无限子弹 超级子弹 无敌并排子弹 总之你自己想怎么改都行

源代码:http://www.cnblogs.com/demonxian3/p/6241755.html