微信飞机大战

您好,本篇文章主要描述如何用面向对象编程思想仿写微信飞机大战。
采用JS脚本来控制HTML5新标签canvas画布,因为只操作一个DOM,画面会更加流畅,很多基于网页开发的小游戏都是用canvas画布实现的。

0 准备工作

首先,我们要准备好各种图片,如飞机的雪碧(精灵)图、子弹图、背景图。

微信飞机大战_第1张图片
图片素材

然后,对整个游戏流程进行构思:

①游戏开始前的图片预加载
②让背景图片动起来
③绘制英雄机,英雄机跟随鼠标移动
④英雄机能发射子弹
⑤绘制3种敌机,赋予它们不同的血量与下落速度
⑥子弹与敌机的碰撞检测
⑦英雄机与敌机的碰撞检测
⑧显示分数,与结束游戏

1 HTML+CSS



    
        
        微信飞机大战
    
    
        //
        
    //引入脚本文件
    
    


2 JS

2.1 所有图片预加载

            //获取画布与画布上下文
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext('2d');
            //分数变量  游戏是否开始变量 英雄机对象
            var score = 0;
            var gameStart = false;
            var theHero = null;

            //  创建对象来接收对应的图片对象
            var bgImg = '';
            var heroImg = '';
            var enemy1Img = '';
            var enemy2Img = '';
            var enemy3Img = '';
            var bullet1Img = '';

            //绘制进度条构造函数
            function Loading(){
                this.width = 220;
                this.height = 12;
                this.x = 50;
                this.y = 258;
            }
    
            //创建进度条原型
            Loading.prototype = {
                //画进度条的外框
                drawStroke : function(){
                    ctx.beginPath();
                    ctx.strokeRect(this.x,this.y,this.width,this.height);
                    ctx.stroke();
                    ctx.closePath();
                },
                //画已加载的填充图
                drawFill : function(){
                    ctx.beginPath();
                    ctx.fillStyle = 'orangered';
                    ctx.fillRect(this.x,this.y,this.width,this.height);
                    ctx.fill();
                    ctx.closePath();
                }
            }
            
            // 预加载函数
            function load(){
                var loadS = new Loading();
                var loadSW = loadS.width;
                loadS.drawStroke();
                var loadF = new Loading();
                loadF.width = 0;
                loadF.drawFill();
                //用一个数组把图片地址保存起来
                var arr = ['img/bg.png','img/hero.png',
                'img/enemy1.png','img/enemy2.png',
                'img/enemy3.png','img/bullet1.png'
                ];
                
                var index = 0;
                //利用循环,创建图片对象
                for(var i = 0;i=arr.length){
                            //当图片全部加载完毕,绘画初始界面
                            theHero = new Hero(heroImg,6);
                            
                            ctx.fillStyle = 'black';
                            ctx.font = '30px Consoles';
                            ctx.fillText('飞机大战',canvas.width/3.5,canvas.height/3);
                            ctx.fillStyle = 'orange';
                            ctx.fillRect(canvas.width/3.5,canvas.height-200,130,50);
                            ctx.fillStyle = 'black';
                            ctx.fillText('开始游戏',canvas.width/3.3,canvas.height-163);
                        }
                    }
                }
            }
            load();
微信飞机大战_第2张图片
加载完成效果图

2.2 为开始按钮添加点击事件

因为在画布内,所以只能根据位置判断是否点击到按钮

canvas.onmousedown = function(e){
                var e = e||window.event;
                var x = e.clientX - canvas.offsetLeft;
                var y = e.clientY - canvas.offsetTop;
                // 开始游戏的框大小内 canvas.width/3.5,canvas.height-200,130,50
                if(x>=canvas.width/3.5&&(x<=canvas.width/3.5+130)&&y>=canvas.height-200&&y

2.3 背景移动函数

利用ctx.drawImage()绘制两张背景图,同时向下移动,当第一张图片移动到底部后就改变图片位置。两张图一直轮播。

            // 设置背景移动量与背景位置变量           
            var bgChange = 1;
            var bgPos = 0;
            // 背景移动函数
            function bgMove(){
                bgPos += bgChange;
                if(bgPos==canvas.height){
                    bgPos = 0;
                    ctx.drawImage(bgImg,0,0);
                }
                ctx.drawImage(bgImg,0,-canvas.height+bgPos);
                ctx.drawImage(bgImg,0,bgPos);               
            }

2.4 各种对象的构造函数

2.4.1 英雄机构造函数

            //传入对象为英雄机图片
            function Hero(obj,health){
                this.obj = obj;     
                this.width = obj.width/health;
                this.height = obj.height;
                //英雄机血量
                this.health = health;
                this.boom = 0;
                //英雄机初始位置
                this.x = canvas.width/2 -this.width/2;
                this.y = canvas.height - this.height;
            }
            Hero.prototype.draw = function(){
                ctx.drawImage(this.obj,this.width*this.boom,0,this.width,this.height,this.x,this.y,this.width,this.height);
            }

2.4.2 子弹构造函数

            //创建一个数组存放子弹对象
            var arrBullet = [];
            function Bullet(x,y,speedY){
                //子弹初始位置
                this.x = theHero.x+31;
                this.y = theHero.y-15;
                //子弹向上运动速度
                this.speedY = speedY || -20;
                this.width = bullet1Img.width;
                this.height = bullet1Img.height
            }
            Bullet.prototype = {
                draw : function(){
                    ctx.drawImage(bullet1Img,this.x,this.y);
                },
                move : function(){
                    this.draw();
                    this.y += this.speedY;
                },
                //当子弹到达顶部,返回布尔值true
                clear : function(){
                    if(this.y<=0){
                        return true;
                    }
                    else{
                        return false;
                    }
                }
            }

2.4.3 敌机构造函数

            //创建一个数组用来存放敌机对象
            var arrEn1 = [];
            //敌机构造函数
            function Enemy(obj,speedY,health,type){
                //传入的对象为 3种不同的敌机图片
                this.obj = obj;
                this.width = obj.width/health;
                this.height = obj.height;
                //敌机出现位置设定为随机
                this.x = rnd(canvas.width-this.width,0);
                this.y = rnd(-canvas.height,-obj.height);
                this.speedY = speedY || 1;
                //敌机血量
                this.health = health;
                //敌机是否被打中
                this.boom = 0;
                //敌机类型
                this.type = type;
            }
            Enemy.prototype = {
                //绘画敌机
                draw : function(){
                    ctx.drawImage(this.obj,this.width*this.boom,0,this.width,this.height,this.x,this.y,this.width,this.height);
                },
                //敌机移动
                move : function(){
                    this.draw();
                    this.y += this.speedY;
                },
                //如果敌机超越画布底部 把清除敌机的布尔值置为true
                clear : function(){
                    if(this.y>=canvas.height){
                        return true;
                    }
                    else{
                        return false;
                    }
                }
            }
            //随机函数
            function rnd(max,min){
                return Math.random()*(max-min+1)+min;
            }

2.5 英雄机跟随鼠标

            canvas.onmousemove = function(e){
                var e = e||window.event;
                var ex = e.clientX - canvas.offsetLeft - 33;
                var ey = e.clientY - canvas.offsetTop - 41;

                theHero.x = ex;
                theHero.y = ey; 
            }

3 主动画函数

            //创造一个变量用来决定敌机出现概率
            var num = 0;
            function move(){
                num++;
                
                if(num==1000){
                    num = 0;
                }
                //每次开始绘画时,先清除画布
                ctx.clearRect(0,0,canvas.width,canvas.height);
                //调用背景移动函数
                bgMove();
                //绘画英雄机
                theHero.draw();
                
                // 创造子弹对象,并把该对象插入到子弹数组
                if(num%5==0){
                    var bullet = new Bullet();
                    arrBullet.push(bullet);
                }
                // 创造小敌机对象(出现几率最大),并把该对象插入到敌机数组
                //(出现几率最大,速度最快2.5,血量最低5)
                if(num%45==0){
                    var en1 = new Enemy(enemy1Img,2.5,5,'en1');
                    arrEn1.push(en1);
                }
                // 创造中敌机对象,并把该对象插入到敌机数组
                //(出现几率最小,速度一般2,血量一般7)
                if(num%160==0){
                    var en3 = new Enemy(enemy3Img,2,7,'en2');
                    arrEn1.push(en3);
                }
                // 创造大敌机对象,并把该对象插入到敌机数组
                //(出现几率最小,速度最慢1.5,血量最高10)
                if(num%360==0){
                    var en2 = new Enemy(enemy2Img,1.5,10,'en3');
                    arrEn1.push(en2);
                }
                
                
                // 遍历子弹数组画子弹
                for(var i =0;i=15000){
                        arrEn1[j].y += arrEn1[j].speedY*1.3;
                    }
                    //如果敌机到达画布底部,从数组中清除该对象
                    if(arrEn1[j].clear()){
                        arrEn1.splice(j,1);
                        j--;
                        continue;
                    }
                    //若没有被清除则绘画该敌机对象
                    arrEn1[j].draw();
                }
                
                // 英雄机与敌机碰撞检测 (矩形碰撞)
                for(var i = 0;iheroR||enT>heroB)){
                        //判断敌机是否爆炸完成,是则清除该敌机对象                      
                        if(arrEn1[i].boom==arrEn1[i].health-1){
                            arrEn1.splice(i,1);
                            i--;
                            continue;
                        }
                        //碰撞到时,英雄机与敌机爆炸增量都自增1
                        else{
                            theHero.boom++;
                            arrEn1[i].boom++;
                        }
                        
                    }
                    //如果英雄机爆炸量与血量相同,则判断游戏结束
                    if(theHero.boom>theHero.health-1){
                            theHero.boom = theHero.health;
                            theHero.draw();
                            //把游戏进行布尔值置为false
                            gameStart = false;
                            //绘画所得分数
                            ctx.fillStyle = 'orangered';
                            ctx.font = '20px Consoles';
                            ctx.fillText('游戏结束,您获得的分数:'+score,10,canvas.height/2);
                            break;
                        }
                }
                //绘画英雄机血量条
                ctx.fillRect(10,canvas.height-20,350*((theHero.health-1-theHero.boom)/theHero.health),10);

                // 判断子弹击中敌机
                for(var i = 0;ienR||btRenB||btB

4 最后效果图

微信飞机大战_第3张图片
游戏进行时
微信飞机大战_第4张图片
游戏结束时

5 总结

原来做一个游戏需要做好很多工作,这是我以前作为一个玩家所无法体会到的,在此感谢给予过我游戏乐趣的前辈们。

你可能感兴趣的:(微信飞机大战)