HTML5+javascript韩顺平坦克大战游戏教程笔记

//css设置 body{padding: 0;margin:0;} .main{width: 510px;height: 510px;margin: 20px auto;position: relative;} #canvas{box-shadow: 2px 2px 2px 3px blue;} #aa{position: absolute;right: -200px;} //html结构
您的浏览器不支持html5 数据
        坦克类的构造,属性有坐标xy,方向direct,行驶速度speed,车身颜色color,考虑到坦克控制,可以把按键运动函数封装到坦克类中,所以可以构造出一个给玩家坦克和敌人坦克共同的父类Tank,减少代码重复
        该类中,坦克运动则根据按键,分别改变坦克坐标,然后分别给方向direct赋值0--3

//抽象一个Tank类
function Tank(x,y,direct,color){
this.x=x;
this.y=y;
this.direct=direct;
this.speed=1;
this.color=color;

    this.moveUp=function(){
        this.y-=this.speed;
        this.direct=0;
    }
    this.moveRight=function(){
        this.x+=this.speed; 
        this.direct=1;
    }
    this.moveDown=function(){
        this.y+=this.speed;
        this.direct=2;
    }
    this.moveLeft=function(){
        this.x-=this.speed;
        this.direct=3;
    }

}
        既然出现Tank父类,那么玩家坦克类Hero就要继承Tank,javascript完成继承机制,采用对象冒充实现。
        简单例子

//父类Animal
function Animal(age,name){
this.age=age;
this.name=name;
}
//子类dog
function Dog(age,name){
//对象冒充
this.Animal_Dog=Animal;
this.Animal_Dog(age,name);
}
//通过继承,可以省去共同属性重复编写,提高代码维护,减少重复

所以,定义玩家坦克Hero类,敌人Enemy类,当然也要给他们定义两个颜色数组,因为他们是简单的颜色拼图坦克

var heroColor=[‘#ba9658’,’#fef26e’];
var enemyColor=[‘#00a2b5’,’#00fefe’];
function Hero(x,y,direct,color){
//通过对象冒充实现继承
this.heroTank=Tank;
this.heroTank(x,y,direct,color);
}
//敌军坦克类
function Enemy(x,y,direct,color){
//继承坦克父类
this.enemyTank=Tank;
this.enemyTank(x,y,direct,color);
}

        类构造完毕,目前父类封装了基础功能,所以呢,接下来就要简单处理按键触发事件,我们使用onkeydown事件触发,按键使用keycode

//按键控制
function controler(event){
event=event||window.event; //兼容浏览器
switch(event.keyCode){
case 87:hero.moveUp();break;
case 68:hero.moveRight();break;
case 83:hero.moveDown();break;
case 65:hero.moveLeft();break;
}
}
window.οnkeydοwn=controler;//加载后,触发

        控制键按下就可以触发,但javascript单独触发事件无法多个按键一起按,想要组合按键,所以接下来的子弹,就会和坦克运动发生阻碍,所以就必须使用另外一套办法,目前我没搞懂。
        接下来绘制坦克函数,坦克有方向,所以要根据方向分别绘制

//画坦克
function drawTank(tank){//传入坦克对象参数
//方向
switch(tank.direct){
case 0://up
case 2://down
context.fillStyle=tank.color[0];//颜色参数
context.beginPath();
context.fillRect(tank.x,tank.y,5,30); context.fillRect(tank.x+15,tank.y,5,30); context.fillRect(tank.x+5,tank.y+10,10,10);
context.fillStyle=tank.color[1];//颜色参数 context.arc(tank.x+10,tank.y+15,4,0,360);
context.fill();
context.strokeStyle=tank.color[1];//颜色参数
context.lineWidth=1.5;
context.moveTo(tank.x+10,tank.y+15);
if(tank.direct==0){
context.lineTo(tank.x+10,tank.y-5);
}else if(tank.direct==2){
context.lineTo(tank.x+10,tank.y+35);
}
context.stroke();
context.closePath();
break;
case 1://right
case 3://left
context.fillStyle=tank.color[0];//颜色参数
context.beginPath();
context.fillRect(tank.x,tank.y,30,5);
context.fillRect(tank.x,tank.y+15,30,5); context.fillRect(tank.x+10,tank.y+5,10,10);
context.fillStyle=tank.color[1];//颜色参数
context.arc(tank.x+15,tank.y+10,4,0,360);
context.fill();
context.strokeStyle=tank.color[1];//颜色参数
context.lineWidth=1.5;
context.moveTo(tank.x+15,tank.y+10);
if(tank.direct==1){
context.lineTo(tank.x+35,tank.y+10);
}else if(tank.direct==3){
context.lineTo(tank.x-5,tank.y+10);
}
context.stroke();
context.closePath();
break;
}

}
        接下来就剩下一个重要函数,刷新,重绘函数,以及模拟多线程的setInterval定时器

//不断刷新画布地图函数
function flashMap(){
//清理画布
context.clearRect(0,0,500,500);
//画出坦克
drawTank(hero);//玩家坦克
drawBullets();//玩家子弹
for(var i=0;i

        接下来要面临比较大的难点,子弹数组以及非常重要的子弹飞行,韩老师使用不断改变子弹坐标,通过作战区函数不断刷新重绘帧来模拟运动
        子弹,无论是玩家还是敌人,都需要子弹,所以为了方便控制,还要编写一个子弹类Bullet

//定义一个子弹类,每个子弹为独立个体,所以需要子弹数组,为了子弹动起来,需要不断刷新作战区需要定时器,子弹应该为全局变量
//坐标,方向跟随坦克方向
function Bullet(x,y,direct,speed){
this.x=x;
this.y=y;
this.direct=direct;
this.speed=speed;
this.isLive=true;//判断子弹是否到达边界
this.timer=null;//每个子弹设置定时器开关,多个物体运动要设置多个定时器,类似多线程
//子弹位置确定
this.run=function run(){
//判断是否碰到边界
if(this.x<=0||this.x>=500||this.y<=0||this.y>=500){
//关闭定时器
clearInterval(this.timer);
//赋值给isLive,表示已死,作为是否刷新绘图判断依据
this.isLive=false;
}
else{
//修改子弹坐标,让子弹飞
switch(this.direct){
case 0:
this.y-=this.speed;
break;
case 1:
this.x+=this.speed;
break;
case 2:
this.y+=this.speed;
break;
case 3:
this.x-=this.speed;
break;
}
}
}
}

        定义好子弹类,那么完成另外一个难点,子弹数组怎么实现,怎么为每个子弹开独立运动定时器?子弹数组元素为子弹对象,设立定时器必须根据数组元素来设立,所以有必要封装到玩家坦克类和敌人坦克类中

//自己坦克Hero类的继承
function Hero(x,y,direct,color){
//通过对象冒充实现继承
this.heroTank=Tank;
this.heroTank(x,y,direct,color);
//我方子弹位置函数封装
this.shotEnemy=function(){
switch(this.direct){
case 0:
heroBullet=new Bullet(this.x+9,this.y-5,this.direct,1);
break;
case 1:
heroBullet=new Bullet(this.x+35,this.y+9,this.direct,1);
break;
case 2:
heroBullet=new Bullet(this.x+9,this.y+35,this.direct,1);
break;
case 3: //右
heroBullet=new Bullet(this.x-5,this.y+9,this.direct,1);
break;
}
//将设置好位置的子弹放入数组中,push方法
heroBullets.push(heroBullet);
//为每个子弹设置定时器,因为外面作战区固定刷新,所以只需要子弹数组长度减去一个即可得到当前子弹
//注意setInterval第一个参数,这里因为要独立出定时器,所以必须传值,也就是字符串模式。否则还是共享同一个定时器
var timer=setInterval(“heroBullets[“+(heroBullets.length-1)+”].run()”,50);
//把子弹数组中子弹开关复制到tmer上面,好进行控制,js是引用传递
heroBullets[heroBullets.length-1].timer=timer;
}
}

        var timer=setInterval("heroBullets["+(heroBullets.length-1)+"].run()",50); 这里就看不懂了,为何我改成匿名函数写法就不行,还是一个定时器,难道是函数调用的是指针,字符串修改的是值副本?晕
        接下来给玩家坦克,敌人坦克绘制,因为有玩家,敌人坦克类了,剩下就是new 一个对象
        敌人坦克有多个,所以还是数组控制

var hero=new Hero(150,150,0,heroColor);
//敌军坦克有多个,用数组存储
var enemyTanks=[];
var count=6;//敌军数量
for(var i=0;i

        绘制子弹

//画出子弹
function drawBullets(){
//如果子弹不为空和子弹不死,没碰到画布边界
for(var i=0;i

你可能感兴趣的:(网页前端)