空战游戏做到这里,己方运动,己方发射子弹,敌方运动,敌方发射子弹,子弹与飞机碰撞,飞机与飞机碰撞都已经具备了,换言之已经可以玩了。

还需要一个奖励升级系统,在上面显示击落敌机数量等,还有己方不幸被击落显示GG等功能。

点此下载源码,并用Chrome打开玩赏。

图例:

源码:

<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
     <title>飞越河谷的战机1.13 19.3.16 13:36 by:逆火狂飙 horn19782016@163.com</title>

     <style>
     *{
        margin:1px;
        padding:1px;
     }
     #canvas{
        background:#ffffff;
     }

     #controls{
        float:left;
     }
     </style>

    </head>

     <body onload="init()">
        <table border="0px">
            <tr>
                <td width="50px"valign="top">
                    <div id="controls">
                        <input id='animateBtn' type='button' value='运动'/>
                    </div>
                </td>
                <td width="100%" align="center">
                    <canvas id="canvas" width="1200px" height="562px" >
                    出现文字表示你的浏览器不支持HTML5
                    </canvas>
                </td>
            </tr>
        </table>
     </body>
</html>
<script type="text/javascript">
<!--
var paused=true;
animateBtn.onclick=function(e){
    paused=! paused;

    if(paused){
        animateBtn.value="运动";

    }else{
        animateBtn.value="暂停";
        window.requestAnimationFrame(animate);
    }
}

var ctx;            // 绘图环境
var bg;                // 背景
var lastTime=0;        // 上次时间,用以计算FPS
var fps=0;            // Frame per second
var myPlane;        // 己方飞机
var myShellMng;        // 己方子弹管理类
var enemyPlaneMng;    // 敌方飞机管理者
var explosionMng;    // 爆炸管理者
var enemyShellMng;  // 敌方子弹管理类

// 初始化,被onload调用
function init(){
    // 创建背景对象
    bg=new Background();

    // 初始化CTX
    var canvas=document.getElementById('canvas');
    canvas.width=bg.width*6;
    canvas.height=bg.height*4;
    ctx=canvas.getContext('2d');

    // +new Date=new Date().getTime();
    lastTime=+new Date;

    // 创建本机对象
    myPlane=new MyPlane(ctx.canvas.width/2,canvas.height-100);

    // 本机子弹管理者
    myShellMng=new MyShellMng();

    // 敌机管理者
    enemyPlaneMng=new EnemyPlaneMng();

    // 爆炸管理者
    explosionMng=new ExplosionMng();

    // 敌方子弹管理者
    enemyShellMng=new EnemyShellMng();

    // 响应键盘按下事件
    canvas.addEventListener('keydown', doKeyDown, true);
    window.addEventListener('keydown', doKeyDown, true);

    // 响应键盘弹起事件
    canvas.addEventListener('keyup', doKeyUp, true);
    window.addEventListener('keyup', doKeyUp, true);

    canvas.focus();
};

//------------------------------------
// 响应键盘按下事件
//------------------------------------
function doKeyDown(e) {
    var keyID = e.keyCode ? e.keyCode :e.which;

    if(keyID === 38 || keyID === 87)  { // up arrow and W
        myPlane.toUp=true;
        e.preventDefault();
    }
    if(keyID === 40 || keyID === 83)  { // down arrow and S
        myPlane.toDown=true;
        e.preventDefault();
    }

    if(keyID === 39 || keyID === 68)  { // right arrow and D
        myPlane.toRight=true;
        e.preventDefault();
    }

    if(keyID === 37 || keyID === 65)  { // left arrow and A
        myPlane.toLeft=true;
        e.preventDefault();
    }

    if(keyID === 32 )  { // SpaceBar
        //  按下和弹起必须成对出现,否则画面会僵
        myPlane.shoot();
        e.preventDefault();
    }
}

//------------------------------------
// 响应键盘弹起事件
//------------------------------------
function doKeyUp(e) {
    var keyID = e.keyCode ? e.keyCode :e.which;

    if(keyID === 38 || keyID === 87)  { // up arrow and W
        myPlane.toUp=false;
        e.preventDefault();
    }
    if(keyID === 40 || keyID === 83)  { // down arrow and S
        myPlane.toDown=false;
        e.preventDefault();
    }

    if(keyID === 39 || keyID === 68)  { // right arrow and D
        myPlane.toRight=false;
        e.preventDefault();
    }

    if(keyID === 37 || keyID === 65)  { // left arrow and A
        myPlane.toLeft=false;
        e.preventDefault();
    }

    if(keyID === 32 )  { // SpaceBar
        // 按下和弹起必须成对出现,否则画面会僵
        e.preventDefault();
    }
}

// 更新各对象状态
function update(){
    myPlane.move();

    myShellMng.move();

    // 判断敌机和本机是否相撞
    enemyPlaneMng.isCrashed(myPlane);

    // 敌机移动
    enemyPlaneMng.move();

    // 判断本方子弹是否与敌机相撞
    myShellMng.probeCrashedEnemyPlane();

    // 补充敌机
    enemyPlaneMng.reload();

    // 移动敌方子弹
    enemyShellMng.move();

    // 判断敌方子弹是否与本机相撞
    enemyShellMng.probeCrashedMyPlane();
}

// 在CTX画出各个对象
function draw(){
    // 清屏
    ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);

    // 画背景
    fps=calculateFps(new Date);
    bg.setOffset(fps);
    var bgImg=bg.getImage();
    ctx.drawImage(bgImg,0,bg.height-bg.Offset,bg.width,bg.Offset,0,0,ctx.canvas.width,4*bg.Offset);
    ctx.drawImage(bgImg,0,0,bg.width,bg.height-bg.Offset,0,4*bg.Offset,canvas.width,canvas.height-4*bg.Offset);

    // 画己方飞机
    myPlane.paint(ctx);

    // 画己方子弹
    myShellMng.paint(ctx);

    // 画敌机
    enemyPlaneMng.paint(ctx);

    // 画爆炸
    explosionMng.paint(ctx);

    // 画敌方子弹
    enemyShellMng.paint(ctx);
}

// 计算FPS
function calculateFps(now){
    var retval=1000/(now-lastTime);
    lastTime=now;
    return retval;
}

// 播放
function animate(){
    if(!paused){
        update();
        draw();
    }

    window.requestAnimationFrame(animate);
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>点类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Point=function(x,y){
    this.x=x;
    this.y=y;
}
Point.prototype={
    x:0,            // 横坐标
    y:0,            // 纵坐标
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<点类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>背景类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Background=function(){
    this.width=104;
    this.height=156;
    this.files=['bgBlue.jpg','bgRiver.jpg','bgSky.jpg','bgVolcano.jpg'];
    this.Offset=0;
    this.velocity=40;
}
Background.prototype={
    width:104,                // 背景图片原始宽度
    height:156,                // 背景图片原始高度
    files:[],                // 图片数组
    Offset:0,                // 偏移值
    velocity:40,            // 背景移动速度
    loopValue:0,            // 循环累加值,用来确定时哪一张图片

    getImage:function(){
        this.loopValue++;
        if(this.loopValue>=3999){
            this.loopValue=0;
        }

        var index=Math.floor(this.loopValue/1000);
        var img=new Image();
        img.src=this.files[index];
        return img;
    },

    setOffset:function(fps){
        this.Offset=this.Offset<this.height?this.Offset+this.velocity/fps:0;
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<背景类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>我方战机类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
MyPlane=function(x,y){
    Point.apply(this,arguments);
    this.types=[
        {width:56,height:41,file:'m1.png',shellCount:1,shellSpeed:4,},
        {width:56,height:41,file:'m2.png',shellCount:2,shellSpeed:4.5,},
        {width:80,height:54,file:'m3.png',shellCount:3,shellSpeed:5,},
        {width:109,height:83,file:'m4.png',shellCount:4,shellSpeed:5.5,},
        {width:109,height:81,file:'m5.png',shellCount:5,shellSpeed:6,},
        {width:109,height:91,file:'m6.png',shellCount:6,shellSpeed:6.5,},
       ];
}

MyPlane.prototype={
    files:[],           // 存储图片的数组
    step:4,                // 每次移动多远
    toLeft:false,        // 是否向左移动
    toRight:false,        // 是否向右移动
    toUp:false,            // 是否向上移动
    toDown:false,        // 是否向下移动
    level:5,            // 等级
    destroyed:false,    // 是否被击毁或撞毁

    paint:function(ctx){
        if(this.destroyed==false){
            var index=this.level;

            if(index>this.types.length-1){
                console.log("非法的本机level值="+this.level);
                index=this.types.length-1;
            }

            var img=new Image();
            img.src=this.types[index].file;
            ctx.drawImage(img,this.x-this.types[index].width/2,this.y-this.types[index].height/2);

            // 标出this,x,this.y所在位置
            //var img2=new Image();
            //img2.src="shoot.png";
            //ctx.drawImage(img2,this.x-5.5,this.y-5.5);
        }
    },

    // 得到飞机的左上角
    getLeftUpPoint:function(){
        var index=this.level;
        var p=new Point(this.x-this.types[index].width/2,this.y-this.types[index].height/2);
        return p;
    },

    // 得到飞机的右上角
    getRightUpPoint:function(){
        var index=this.level;
        var p=new Point(this.x+this.types[index].width/2,this.y-this.types[index].height/2);
        return p;
    },

    // 得到飞机的左下角
    getLeftDownPoint:function(){
        var index=this.level;
        var p=new Point(this.x-this.types[index].width/2,this.y+this.types[index].height/2);
        return p;
    },

    // 得到飞机的右下角
    getRightDownPoint:function(){
        var index=this.level;
        var p=new Point(this.x+this.types[index].width/2,this.y+this.types[index].height/2);
        return p;
    },

    move:function(){
        // 加入边界判断 2019年3月13日19点16分
        var type=this.types[this.level].file;

        if(this.x<0){
            this.x=0;
            this.toLeft=false;
        }
        if(this.x>ctx.canvas.width){
            this.x=ctx.canvas.width;
            this.toRight=false;
        }

        if(this.y<0){
            this.y=0;
            this.toUp=false;
        }

        if(this.y>ctx.canvas.height){
            this.y=ctx.canvas.height;
            this.toDown=false;
        }

        // 运动
        if(this.toLeft==true && this.destroyed==false){
            this.x-=this.step;
        }
        if(this.toRight==true && this.destroyed==false){
            this.x+=this.step;
        }
        if(this.toUp==true && this.destroyed==false){
            this.y-=this.step;
        }
        if(this.toDown==true && this.destroyed==false){
            this.y+=this.step;
        }
    },

    //  本机开炮
    shoot:function(){
        if(this.destroyed==false){
            var index=this.level;

            // 得到炮弹
            var shellCount=this.types[index].shellCount;
            var shells=myShellMng.fetch(shellCount);

            // 用来控制炮弹发射位置

            var xLeft=this.x-this.types[index].width/2;
            var offset=this.types[index].width/(shellCount+1);

            for(var i=0;i<shellCount;i++){
                var s=shells[i];

                s.x=xLeft+(i+1)*offset;
                s.y=this.y;
                s.speed=this.types[index].shellSpeed;
            }
        }
    },

    // 根据等级取得炮弹数量
    /*getShellNum:function(){
        if(this.level==0){
            return 1;
        }
        else if(this.level==1){
            return 2;
        }
        else if(this.level==2){
            return 3;
        }
        else if(this.level==3){
            return 4;
        }
        else if(this.level==4){
            return 5;
        }
        else if(this.level==5){
            return 6;
        }
        else if(this.level==6){
            return 7;
        }
        else if(this.level==7){
            return 8;
        }
        else{
            return 9;
        }
    },*/

    // 根据等级取得炮弹速度
    /*getShellSpeed:function(){
        if(this.level==0){
            return 2;
        }
        else if(this.level==1){
            return 2;
        }
        else if(this.level==2){
            return 4;
        }
        else if(this.level==3){
            return 4;
        }
        else if(this.level==4){
            return 5;
        }
        else if(this.level==5){
            return 5;
        }
        else if(this.level==6){
            return 6;
        }
        else if(this.level==7){
            return 7;
        }
        else{
            return 8;
        }
    },*/

    // 判断以x,y为坐标的点是否进入本机机四角范围内
    isWithinLimits:function(x,y){
        var index=this.level;

        var left=this.x-this.types[index].width/2;
        var top=this.y-this.types[index].height/2;
        var width=this.types[index].width;
        var height=this.types[index].height;

        if(left<x && x<left+width && top<y && y<top+height){
            return true;
        }else{
            return false;
        }
    },

    // 看地方炮弹是否命中本机
    isShooted:function(shell){
        if(shell.destroyed==true){
            return false;
        }

        // 如果炮弹打中本机范围
        if(this.isWithinLimits(shell.x,shell.y)){
            this.destroyed=true;
            shell.destroyed=true;

            // 制造爆炸
            explosionMng.fire(this.x,this.y);

            // 游戏结束

            return true;
        }

        return false;
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<我方战机类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>我方炮弹类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
MyShell=function(x,y){
    Point.apply(this,arguments);

    this.types=[
        {width:11,height:11,file:'shell0.png'},
        {width:11,height:11,file:'shell1.png'},
        {width:11,height:11,file:'shell2.png'},
        {width:11,height:11,file:'shell3.png'},
        {width:11,height:11,file:'shell4.png'},
        {width:11,height:11,file:'shell5.png'},
        {width:11,height:11,file:'shell6.png'},
        {width:18,height:18,file:'shell7.png'},
    ];

}
MyShell.prototype={
    types:[],        // 炮弹型号
    destroyed:false,// 是否被敌机撞毁
    visible:true,    // 是否在CTX显示范围内
    level:3,        // 等级,用以决定炮弹型号
    speed:4,        // 炮弹速度(己方炮弹向上飞行)

    paint:function(ctx){
        if(this.visible==false){
            return;
        }

        if(this.destroyed==false){
            // 没被击毁显示炮弹型号
            var img=new Image();
            var index=this.level;
            img.src=this.types[index].file;
            ctx.drawImage(img,this.x-this.types[index].width/2,this.y-this.types[index].height/2);
        }
    },

    move:function(){
        // 设置越界不可见
        if(this.x<0){
            this.visible=false;
        }
        if(this.x>ctx.canvas.width){
            this.visible=false;
        }

        if(this.y<0){
            this.visible=false;
        }

        if(this.y>ctx.canvas.height){
            this.visible=false;
        }

        if(this.visible==true && this.destroyed==false){
            this.y-=this.speed;
        }
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<我方炮弹类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>我方炮弹管理者类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>19.3.16
MyShellMng=function(){
    shells=new Array();
}
MyShellMng.prototype={
    shells:[],        // 己方炮弹对象数组

    paint:function(ctx){
        for(var i=0;i<this.shells.length;i++){
            var s=this.shells[i];
            s.paint(ctx);
        }
    },

    // 取出子弹,count为个数
    fetch:function(count){
        var retval=new Array();

        console.log("原有己方炮弹数量=",this.shells.length);
        // 先取原有的炮弹
        for(var i=0;i<this.shells.length;i++){
            var s=this.shells[i];

            if(s.visible==false || s.destroyed==true){
                s.destroyed=false;
                s.visible=true;

                if(retval.length<count){
                    retval.push(s);
                }
            }
        }

        // 不足再创建新的炮弹
        while(retval.length<count){
            var s=new MyShell(0,0);
            this.shells.push(s);
            retval.push(s);
        }

        console.log("现有己方炮弹数量=",this.shells.length);

        return retval;
    },

    // 移动炮弹
    move:function(){
        for(var i=0;i<this.shells.length;i++){
            var s=this.shells[i];
            s.move();
        }
    },

    // 判断炮弹是否撞到敌机
    probeCrashedEnemyPlane:function(){
        for(var i=0;i<this.shells.length;i++){
            var s=this.shells[i];
            if(s.visible==true && s.destroyed==false){
                if(enemyPlaneMng.isShooted(s)==true){
                    s.destroyed=true;
                    return;
                }
            }
        }
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<我方炮弹管理者类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//  常规函数:角度得到弧度
function getRad(degree){
    return degree/180*Math.PI;
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>敌方飞机类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
EnemyPlane=function(x,y,level){
    Point.apply(this,arguments);
    this.level=level;

    this.types=[
        {width:117,height:64,file:'e0.png',shellCount:1,shootInterval:300,shellSpeed:3 ,reciprocatingRadius:0},
        {width:117,height:64,file:'e1.png',shellCount:2,shootInterval:270,shellSpeed:4 ,reciprocatingRadius:0.5},
        {width:100,height:77,file:'e2.png',shellCount:3,shootInterval:240,shellSpeed:5 ,reciprocatingRadius:1},
        {width:117,height:85,file:'e3.png',shellCount:4,shootInterval:210,shellSpeed:6 ,reciprocatingRadius:1.5},
        {width:117,height:93,file:'e4.png',shellCount:5,shootInterval:180,shellSpeed:7 ,reciprocatingRadius:2},
        {width:117,height:93,file:'e5.png',shellCount:6,shootInterval:150,shellSpeed:8 ,reciprocatingRadius:2.25},
        {width:117,height:96,file:'e6.png',shellCount:7,shootInterval:120,shellSpeed:9 ,reciprocatingRadius:2.5},
        {width:117,height:99,file:'e7.png',shellCount:8,shootInterval:90 ,shellSpeed:10,reciprocatingRadius:2.75},
    ];
}
EnemyPlane.prototype={
    types:[],            // 飞机型号数组
    destroyed:false,    // 是否被击毁
    level:7,            // 等级,用此取飞机型号
    visible:true,        // 是否在ctx显示范围内
    speed:2,            // 敌机向下飞行的速度

    paint:function(ctx){
        // 不可见则不显示
        if(this.visible==false){
            return;
        }

        if(this.destroyed==false){
            // 没被击毁显示飞机型号
            var img=new Image();
            var index=this.level;

            if(index>this.types.length-1){
                console.log("非法的敌机level值="+this.level);
                index=this.types.length-1;
            }

            img.src=this.types[index].file;

            ctx.drawImage(img,this.x-this.types[index].width/2,this.y-this.types[index].height/2);

            // 标出本机下x,y坐标
            //var img2=new Image();
            //img2.src="shoot.png";
            //ctx.drawImage(img2,this.x-5.5,this.y-5.5);
        }
    },

    // 判断以x,y为坐标的点是否进入敌机四角范围内
    isWithinLimits:function(x,y){
        var index=this.level;

        var left=this.x-this.types[index].width/2;
        var top=this.y-this.types[index].height/2;
        var width=this.types[index].width;
        var height=this.types[index].height;

        if(left<x && x<left+width && top<y && y<top+height){

            return true;
        }else{
            return false;
        }
    },

    // 敌机飞行
    move:function(){
        // 设置越界不可见
        if(this.x<0){
            this.visible=false;
        }
        if(this.x>ctx.canvas.width){
            this.visible=false;
        }

        if(this.y<0){
            this.visible=false;
        }

        if(this.y>ctx.canvas.height){
            this.visible=false;
        }

        if(this.visible){
            var index=this.level;

            this.y+=this.speed;
            this.x+=this.types[index].reciprocatingRadius*Math.sin(getRad(this.y));

            //  行动中随机开枪
            var rnd=this.getRndBetween(0,this.types[index].shootInterval);// 上限越大打得越慢,这个值可以叫ShootInterval
            if(rnd<1){
                this.shoot();
            }
        }
    },

    // 得到随机数
    getRndBetween:function (lowerLimit,upperLimit){
        return Math.floor(Math.random()*(upperLimit-lowerLimit+1))+lowerLimit;
    },

    //  敌机开炮
    shoot:function(){
        if(this.destroyed==false){
            var index=this.level;

            // 得到炮弹
            var shellCount=this.types[index].shellCount;
            var shells=enemyShellMng.fetch(shellCount);

            // 用来控制炮弹发射位置

            var xLeft=this.x-this.types[index].width/2;
            var offset=this.types[index].width/(shellCount+1);

            for(var i=0;i<shellCount;i++){
                var s=shells[i];

                s.x=xLeft+(i+1)*offset;
                s.y=this.y;
                s.speed=this.types[index].shellSpeed;
            }
        }
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<敌方飞机类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>敌方飞机管理类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
EnemyPlaneMng=function(x,y){
    Point.apply(this,arguments);

    this.planes=new Array();
    this.planes.push(new EnemyPlane(ctx.canvas.width/2,20,0));
    //this.planes.push(new EnemyPlane(ctx.canvas.width/2-80,20,1));
    //this.planes.push(new EnemyPlane(ctx.canvas.width/2+80,20,3));
}
EnemyPlaneMng.prototype={
    planes:[],

    // 得到lowerLimit到upperlimit(包括端点值)的随机整数
    getRndBetween:function (lowerLimit,upperLimit){
        return Math.floor(Math.random()*(upperLimit-lowerLimit+1))+lowerLimit;
    },

    // 重新装载飞机
    reload:function(){
        var count=this.getAlivePlaneCount();

        if(count==0){
            var i=this.getRndBetween(0,this.planes.length-1);

            var plane=this.planes[i];
            plane.visible=true;
            plane.destroyed=false

            plane.x=ctx.canvas.width/2+this.getRndBetween(-100,100);
            plane.y=this.getRndBetween(20,30);
            plane.level=this.getRndBetween(0,7);

        }
    },

    // 得到屏幕上飞机活着的飞机数目
    getAlivePlaneCount:function(){
        var retval=0;
        for(var i=0;i<this.planes.length;i++){
            var plane=this.planes[i];
            if(plane.visible==true && plane.destroyed==false){
                retval++;
            }
        }

        return retval;
    },

    paint:function(ctx){
        for(var i=0;i<this.planes.length;i++){
            var plane=this.planes[i];
            plane.paint(ctx);
        }
    },

    move:function(){
        for(var i=0;i<this.planes.length;i++){
            var plane=this.planes[i];
            plane.move();
        }
    },

    isShooted:function(shell){
        if(shell.destroyed==true){
            return false;
        }

        for(var i=0;i<this.planes.length;i++){
            var plane=this.planes[i];

            if(plane.visible==true && plane.destroyed==false){

                if(plane.isWithinLimits(shell.x,shell.y)){
                    plane.destroyed=true;
                    shell.destroyed=true;

                    // 制造爆炸
                    explosionMng.fire(shell.x,shell.y);

                    // 敌机重载
                    enemyPlaneMng.reload();

                    return true;
                }
            }
        }

        return false;
    },

    // 看主角飞机是否与敌机相撞
    isCrashed:function(rolePlane){
        if(rolePlane.destroyed==true){
            return false;
        }

        // 得到本机四角坐标
        var p1=rolePlane.getLeftUpPoint();
        var p2=rolePlane.getRightUpPoint();
        var p3=rolePlane.getLeftDownPoint();
        var p4=rolePlane.getRightDownPoint();

        for(var i=0;i<this.planes.length;i++){
            var ep=this.planes[i];

            if(ep.visible==true && ep.destroyed==false){

                if(ep.isWithinLimits(p1.x,p1.y) || ep.isWithinLimits(p2.x,p2.y) || ep.isWithinLimits(p3.x,p3.y) || ep.isWithinLimits(p4.x,p4.y)){

                    ep.destroyed=true;// 敌机撞毁
                    explosionMng.fire(ep.x,ep.y);// 制造爆炸

                    // 本机撞毁后不用敌机重载
                    //enemyPlaneMng.reload();

                    rolePlane.destroyed=true;// 本机撞毁
                    explosionMng.fire(rolePlane.x,rolePlane.y);// 制造爆炸

                    // 游戏结束

                    return true;
                }
            }
        }

        return false;
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<敌方飞机管理类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>爆炸类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Explosion=function(x,y){
    Point.apply(this,arguments);

    this.types=[
        {width:105,height:100,file:'explosion0.png'},
        {width:105,height:100,file:'explosion1.png'},
        {width:105,height:100,file:'explosion2.png'},
        {width:105,height:100,file:'explosion3.png'},
        {width:105,height:100,file:'explosion4.png'},
        {width:105,height:100,file:'explosion5.png'},
    ];
}
Explosion.prototype={
       types:[],        // 爆炸图片
    destroyTime:0,    // 被摧毁时间

    paint:function(ctx){
        var index=Math.floor(this.destroyTime);

        if(index<this.types.length){
            this.destroyTime+=0.05;
            var img=new Image();
            img.src=this.types[index].file;
            ctx.drawImage(img,this.x-this.types[index].width/2,this.y-this.types[index].height/2);
        }
    },

    // 看这个爆炸对象是否使用过
    isUsed:function(){
        return this.destroyTime>=this.types.length;
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<爆炸类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>爆炸管理类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ExplosionMng=function(x,y){
    exps=new Array();
}
ExplosionMng.prototype={
       exps:[],        // 爆炸数组

    paint:function(ctx){
        for(var i=0;i<exps.length;i++){
            var e=exps[i];
            e.paint(ctx);
        }
    },

    // 制作一次爆炸,使用这种方式,可最大程度利用现有对象,而不是创建一堆用不上的变量
    fire:function(x,y){
        var exp=null;

        for(var i=0;i<exps.length;i++){
            var e=exps[i];
            //console.log('e.isUsed=',e.isUsed())

            if(e.isUsed()==true){
                exp=e;
                exp.x=x;
                exp.y=y;
                exp.destroyTime=0;
                //console.log('使用一个原有对象',exp)
                break;
            }
        }

        if(exp==null){
            exp=new Explosion(x,y);
            exps.push(exp);
            //console.log('创建一个新对象',exp)
        }

        //console.log('爆炸对象个数=',exps.length)
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<爆炸管理类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>敌方炮弹类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 19.3.16
EnemyShell=function(x,y){
    Point.apply(this,arguments);

    this.types=[
        {width:11,height:11,file:'shell0.png'},
        {width:11,height:11,file:'shell1.png'},
        {width:11,height:11,file:'shell2.png'},
        {width:11,height:11,file:'shell3.png'},
        {width:11,height:11,file:'shell4.png'},
        {width:11,height:11,file:'shell5.png'},
        {width:11,height:11,file:'shell6.png'},
        {width:18,height:18,file:'shell7.png'},
    ];

}
EnemyShell.prototype={
    types:[],        // 炮弹型号
    destroyed:false,// 是否被敌机撞毁
    visible:true,    // 是否在CTX显示范围内
    level:0,        // 等级,用以决定炮弹型号
    speed:4,        // 炮弹速度(敌方炮弹向下飞行)

    paint:function(ctx){
        if(this.visible==false){
            return;
        }

        if(this.destroyed==false){
            // 没被击毁显示炮弹型号
            var img=new Image();
            var index=this.level;
            img.src=this.types[index].file;
            ctx.drawImage(img,this.x-this.types[index].width/2,this.y-this.types[index].height/2);
        }
    },

    move:function(){
        // 设置越界不可见
        if(this.x<0){
            this.visible=false;
        }
        if(this.x>ctx.canvas.width){
            this.visible=false;
        }

        if(this.y<0){
            this.visible=false;
        }

        if(this.y>ctx.canvas.height){
            this.visible=false;
        }

        if(this.visible==true && this.destroyed==false){
            this.y+=this.speed;
        }
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<敌方炮弹类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>敌方炮弹管理者类定义开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>19.3.16
EnemyShellMng=function(){
    shells=new Array();
}
EnemyShellMng.prototype={
    shells:[],        // 己方炮弹对象数组

    paint:function(ctx){
        for(var i=0;i<this.shells.length;i++){
            var s=this.shells[i];
            s.paint(ctx);
        }
    },

    // 取出子弹,count为个数
    fetch:function(count){
        var retval=new Array();

        console.log("原有敌方炮弹数量=",this.shells.length);
        // 先取原有的炮弹
        for(var i=0;i<this.shells.length;i++){
            var s=this.shells[i];

            if(s.visible==false || s.destroyed==true){
                s.destroyed=false;
                s.visible=true;

                if(retval.length<count){
                    retval.push(s);
                }
            }
        }

        // 不足再创建新的炮弹
        while(retval.length<count){
            var s=new EnemyShell(0,0);
            this.shells.push(s);
            retval.push(s);
        }

        console.log("现有敌方炮弹数量=",this.shells.length);

        return retval;
    },

    // 移动炮弹
    move:function(){
        for(var i=0;i<this.shells.length;i++){
            var s=this.shells[i];
            s.move();
        }
    },

    // 判断炮弹是否撞到本机
    probeCrashedMyPlane:function(){
        for(var i=0;i<this.shells.length;i++){
            var s=this.shells[i];
            if(s.visible==true && s.destroyed==false && myPlane.destroyed==false){

                if(myPlane.isShooted(s)==true){
                    s.destroyed=true;
                    return;
                }
            }
        }
    },
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<敌方炮弹管理者类定义结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//-->
</script>

2019年3月16日15点45分

[Canvas]空战游戏 已经可以玩了 1.13Playable的更多相关文章

  1. [canvas]空战游戏1.18

    空战游戏到今天可以玩了,玩法还是方向键(或AWSD)控制飞机位置,空格键开炮,吃五星升级,被敌机打中降级直到击落,与敌机相撞则GG. 点此下载程序1.16版,用CHrome打开index.html试玩 ...

  2. [Canvas]空战游戏进阶 增加己方子弹管理类

    点此下载源码,可用Chrome打开观看. 图例: 代码: <!DOCTYPE html> <html lang="utf-8"> <meta http ...

  3. [Canvas]空战游戏进阶 增加爆炸管理类

    点此下载源码,欲观看效果请用Chrome打开index.html 图例: 源码: <!DOCTYPE html> <html lang="utf-8"> & ...

  4. [Canvas]空战游戏进阶 增加发射子弹 敌机中弹爆炸功能

    点此下载源码. 图例: 源码: <!DOCTYPE html> <html lang="utf-8"> <meta http-equiv=" ...

  5. 两个Canvas小游戏

    或许连小游戏都算不上,可以叫做mini游戏. 没有任何框架或者稍微有点深度的东西,所以有js基础的或者要追求炫酷效果的可以直接ctrl+w了. 先贴出两个游戏的试玩地址: 是男人就走30步 是男人就忍 ...

  6. canvas小游戏——flappy bird

    前言 如果说学编程就是学逻辑的话,那锻炼逻辑能力的最好方法就莫过于写游戏了.最近看了一位大神的fly bird小游戏,感觉很有帮助.于是为了寻求进一步的提高,我花了两天时间自己写了一个canvas版本 ...

  7. 如何开发一个简单的HTML5 Canvas 小游戏

    原文:How to make a simple HTML5 Canvas game 想要快速上手HTML5 Canvas小游戏开发?下面通过一个例子来进行手把手教学.(如果你怀疑我的资历, A Wiz ...

  8. canvas 进入游戏点击时苹果手机为什么会闪

    canvas 进入游戏点击时苹果手机为什么会闪 ?? 大神门 谁有解决办法???

  9. 【30分钟学完】canvas动画|游戏基础(1):理论先行

    前言 本文虽说是基础教程,但这是相对动画/游戏领域来说,在前端领域算是中级教程了,不适合前端小白或萌新.阅读前请确保自己对前端三大件(JavaScript+CSS+HTML)的基础已经十分熟悉,而且有 ...

随机推荐

  1. 在 Wiki 标记中添加无序列表

    项目:在 Wiki 标记中添加无序列表在编辑一篇维基百科的文章时,你可以创建一个无序列表,即让每个列表项占据一行,并在前面放置一个星号.但是假设你有一个非常大的列表,希望添加前面的星号.你可以在每一行 ...

  2. 浪里个浪 FZU - 2261

    TonyY是一个喜欢到处浪的男人,他的梦想是带着兰兰姐姐浪遍天朝的各个角落,不过在此之前,他需要做好规划. 现在他的手上有一份天朝地图,上面有n个城市,m条交通路径,每条交通路径都是单行道.他已经预先 ...

  3. hust 1010 The Minimum Length(循环节)【KMP】

    <题目链接> 题目大意: 有一个字符串A,一次次的重写A,会得到一个新的字符串AAAAAAAA.....,现在将这个字符串从中切去一部分得到一个字符串B,例如有一个字符串A="a ...

  4. springboot2.0 redis EnableCaching的配置和使用

    一.前言 关于EnableCaching最简单使用,个人感觉只需提供一个CacheManager的一个实例就好了.springboot为我们提供了cache相关的自动配置.引入cache模块,如下. ...

  5. python & MySQLdb(one)

    python开发过程中用到数据库无外乎MYSQL,Mangodb,redis三种,三者数据库使用可能存在差异,但在一些基础的语句使用时都是大同小异的,这阶段学习了一些基础操作,记录下 add: # - ...

  6. Why Did the Cow Cross the Road III HYSBZ - 4991 -CDQ-逆序数

    HYSBZ - 4991 题意: 第一列 1-n的排列 ,第二列 1-n的排列.  相同数字连边  ,问  有多少组 数字 是有交点的并且 绝对值之差>K思路:处理一下 1-n 在第一列的位置, ...

  7. AGC 030B.Tree Burning(贪心)

    题目链接 \(Description\) 有一个长为\(L\)的环,上面有\(n\)棵树,坐标分别为\(a_i\).初始时在原点. 每次你可以选择顺时针或逆时针走到第一棵没有被烧掉的树,停在这个位置, ...

  8. 潭州课堂25班:Ph201805201 django 项目 第四十课 后台 文章发布,更新实现,热门新闻管理,轮播图管理(课堂笔记)

    把图片上传到 七牛云,必须经过后台的许可, 在虚拟机中安装七牛云所需模块pip install qiniu # 创建utils/secrets/qiniu_secret_info.py文件 # 从七牛 ...

  9. js中使用将json数组 转换为json将一个包含对象的数组用以创建一个包含新重新格式化对象的新数组

    1.使用reduce: let arr = [{ "code": "badge", "priceList": [{ "amount ...

  10. C#中#region和#endregion的用法

    一.用法说明 #region 说明 Program1 #endregion 二.作用 (1)注释其中间的代码段 (2)折叠中间的代码块(折叠后的说明文字为#region后面的说明)