zoukankan      html  css  js  c++  java
  • web版canvas做飞机大战游戏 总结

      唠唠:两天的时间跟着做了个飞机大战的游戏,感觉做游戏挺好的。说是用html5做,发现全都是js。说js里一切皆为对象,写的最多的还是函数,都是函数调用。对这两天的代码做个总结,希望路过的大神指点一下,我对这个游戏的思路,可改进优化的代码。

      先说一下游戏的基本内容: 打飞机(不要想歪了),有鼠标控制移动英雄机,子弹自动射击;敌机从上而下,有三种敌机;

      先说下HTML代码(主要就是这一行):  

    <canvas id="canFly" width="480" height="650"></canvas>

    一、对这个游戏的的基本数据状态做定义

      主要包括:

        游戏的状态: 开始状态 英雄机入场状态 游戏进行状态 暂停状态 gameOver;得分 英雄机的生命 

     1 var canvas = document.getElementById("canFly");//获取canvas元素
     2 //创建画布对象
     3 var context = canvas.getContext("2d");
     4 //游戏的基本数据
     5 var gameData = {
     6     state : this.START,
     7     //游戏状态
     8     START : 0,//开始界面状态
     9     STARTING : 1,//入场动画过渡状态
    10     RUNNING : 2,//游戏运行状态
    11     PAUSED : 3,//暂停
    12     GAMEOVER : 4,//游戏结束
    13     //英雄机生命
    14     heroLife : 3,
    15     //得分
    16     score : 0,
    17     //画布宽高
    18     HEIGHT : canvas.height
    19 }
    View Code

    二、对图片资源的加载及初始化相关数据

     1             /*-- 加载游戏图片 -------------------------------------------------------------------*/
     2             //背景图片
     3             var bgImg = new Image();
     4             bgImg.src="images/background.png";
     5             //logo图片
     6             var startLogo = new Image();
     7             startLogo.src = "images/start.png";
     8             //加载飞机入场动画
     9             var loadings = [];
    10             loadings[0] = new Image();
    11             loadings[0].src="Images/game_loading1.png";
    12             loadings[1] = new Image();
    13             loadings[1].src="Images/game_loading2.png";
    14             loadings[2] = new Image();
    15             loadings[2].src="Images/game_loading3.png";
    16             loadings[3] = new Image();
    17             loadings[3].src="Images/game_loading4.png";
    18             //加载英雄机图片
    19             var heros = [];
    20             heros[0] = new Image();
    21             heros[0].src="images/hero1.png";
    22             heros[1] = new Image();
    23             heros[1].src="images/hero2.png";
    24             //英雄机爆破动画图片
    25             heros[2] = new Image();
    26             heros[2].src="images/hero_blowup_n1.png";
    27             heros[3] = new Image();
    28             heros[3].src="images/hero_blowup_n2.png";
    29             heros[4] = new Image();
    30             heros[4].src="images/hero_blowup_n3.png";
    31             heros[5] = new Image();
    32             heros[5].src="images/hero_blowup_n4.png";
    33             //加载子弹的图片
    34             var bullet = [];
    35             bullet[0] = new Image();
    36             bullet[0].src = "images/bullet1.png";
    37             ...
    View Code
     1             /*-- 初始化游戏内容相关数据 --*/
     2             //初始化游戏背景图片数据
     3             var SKY = {
     4                 imgs : bgImg,//背景图片
     5                 width : 480,//图片宽度
     6                 height : 852 //图片高度
     7             }
     8             //初始化英雄机入场动画图片数据
     9             var LOADING = {
    10                 imgs : loadings,
    11                 width : 186,//图片宽度
    12                 height : 38,//图片高度
    13                 sum : loadings.length //图片个数
    14             }
    15             //初始化英雄机的数据
    16             var HERO = {
    17                 imgs : heros,
    18                 width : 99,
    19                 height : 124,
    20                 sum : heros.length,
    21                 length : 2//我方飞机正常图片个数
    22             }
    23             //初始化子弹的数据
    24             var BULLET = {//默认子弹
    25                 imgs : bullet,
    26                 width : 9,
    27                 height : 21,
    28                 sum : bullet.length
    29             }
    30 .......
    View Code

    三、公用构造器及对象实例化

      定义一个公用的构造器函数,这是我写这个游戏认最大的收获了,在这里体会到了面向对象的思想;相当于定义一个基础类,所有的构造器都用公用构造器函数进行初始化,提高代码的复用,然而在我的优化过程中仅仅只是节省了50多行的代码。

      公共构造器函数:在这里定义了图片的宽高,图片对象是否执行爆破,是否删除,图片绘制坐标等一些公共的属性和方法

     1             /*-- 通用构造器对象 前端代码尽量地使用通用代码 -------------------------------------------------------------------------------------------------------*/
     2             function Compant(config){
     3                 //加载图片
     4                 this.imgs = config.imgs;
     5                 //图片的宽度和高度
     6                 this.width = config.width;
     7                 this.height = config.height;
     8                 this.sum = config.sum;
     9                 this.length = config.length;
    10                 // 敌方飞机具有以下属性
    11                 this.type = config.type;//敌机类型
    12                 this.life = config.life;//敌机声明值
    13                 this.score = config.score;//敌机分数
    14                 // 设置相对速度
    15                 this.time = 0;
    16                 // 设置图片的索引值
    17                 this.index = 0;
    18                 // 是否执行爆破动画的标识
    19                 this.down = false;
    20                 // 是否删除标识
    21                 this.canDelete = false;
    22                 //绘图坐标
    23                 this.x = 0;
    24                 this.y = 0;
    25                 // 绘制方法
    26                 this.paint = function(){
    27                     context.drawImage(this.imgs[this.index],this.x,this.y);
    28                 }
    29                 // 移动方法
    30                 this.step = function(){}
    31                 // 执行撞击后的逻辑方法
    32                 this.bang = function(){}
    33             }
    View Code

       继承实例化:

     1             //---背景
     2             //创建背景图片的构造器
     3             function BgSky(config){
     4                 //调用通用构造器初始化
     5                 Compant.call(this,config);
     6                 //图片绘制高度变量
     7                 this.y1 = -this.height;
     8                 this.y2 = 0;
     9                 //定义绘制方法
    10                 this.paint = function(){            
    11                     context.drawImage(this.imgs,0,this.y1);//第一张图片
    12                     context.drawImage(this.imgs,0,this.y2);//第二张图片
    13                 }
    14                 //背景heigth运动方法
    15                 this.step = function(){
    16                     this.time++;
    17                     if (this.time%3==0)
    18                     {//控制背景图片height值的增加
    19                         this.y1++;//图片运动下一帧
    20                         this.y2++;
    21                         //图片移动处画布后将y坐标重置为-height 实现图片衔接滚动
    22                         this.y1>this.height&&(this.y1 = -this.height);
    23                         this.y2>this.height&&(this.y2 = -this.height);
    24                         this.time=1;//重置移动时间
    25                     }
    26                 }
    27             }
    28             //创建图片对象
    29             var sky = new BgSky(SKY);
    30             
    31             //---英雄机入场动画构造器
    32             function Loading(config){
    33                 Compant.call(this,config);
    34                 //定义绘制
    35                 this.paint = function(){
    36                     //绘制飞机入场动画图片
    37                     context.drawImage(this.imgs[this.index],0,gameData.HEIGHT-this.height);
    38                 }
    39                 //定义入场动画
    40                 this.step = function(){
    41                     this.time++;
    42                     if (this.time%20==0)
    43                     {//实现动画的播放速度
    44                         this.index++;//下一帧动画
    45                         if (this.index==this.sum)
    46                         {//判断动画结束后,更改游戏的状态,进入第三阶段游戏阶段
    47                             gameData.state=gameData.RUNNING;    
    48                             this.time=0;//重置动画时间
    49                         }
    50                     }
    51                 }
    52             }
    53             //创建飞机入场动画的对象
    54             var loading = new Loading(LOADING);
    View Code

      利用这种方式将所有的对象都进行实例化,并添加相应的方法

    四、英雄机的子弹发射

      英雄机的子弹发射是自动,就是说只要控制好装弹的频率就可以了;英雄机发射子弹就是向子弹数组中添加子弹

    bullets[bullets.length] = new Bullet(BULLET);;//向子弹数组中添加子弹

       子弹的移动,撞击,删除等功能在子弹的构造函数中定义,英雄机只管装弹的频率;

      子弹的绘制:

     1             function paintBullets(){
     2                 for (var i=0, length=bullets.length;  i<length; i++)
     3                 {
     4                     bullets[i].paint();//绘制当前子弹
     5                     if (gameData.state==gameData.RUNNING)
     6                     {//游戏运行中时移动子弹
     7                         bullets[i].step();//移动子弹
     8                     }
     9                 }
    10             }

      删除子弹的判断:

    1             function clearStep(){
    2                 for (var i = bullets.length-1; i>=0 ; i--)
    3                 {
    4                     if (bullets[i].y<=-bullets[i].height || (bullets[i].canDelete))
    5                     {
    6                         bullets.splice(i,1);//删除当前超出屏幕的子弹和撞机的子弹
    7                     }
    8                 }
    9             }
          //这个函数可以跟上边的合并到一起

      

    五、敌机的相关设置

      敌机的创建: 应为有三种类型的敌机,按照几率小的最多,中飞机的其次,打飞机满屏只能有一个

     1             //创建用于创建敌方飞机的函数
     2             function createEnemies(){
     3                 /*创建敌方飞机 - 小,中,大*/
     4                 var num = Math.floor(Math.random()*100);
     5                 if (num < 80)
     6                 {//小飞机
     7                     enemies[enemies.length] = new Enemy(ENEMY1);
     8                 }else if (num < 90)
     9                 {//中飞机
    10                     enemies[enemies.length] = new Enemy(ENEMY2);
    11                 }else {
    12                     //大飞机只能存在一个
    13                     if (enemies.length > 0 && enemies[0].type != 2)
    14                     {
    15                         enemies.unshift(new Enemy(ENEMY3));//将大飞机添加到数组开头,这样每次判断数组第一个就可以知道
    16                     }
    17                 }
    18             }

       对敌机的绘制,检测敌机是否超出屏幕,是否被打中,是否需要爆炸,是否和英雄机相撞等

     1             function paintEnemiesAndCheckHit(){
     2                 for (var i=0; i<enemies.length; i++)
     3                 {//遍历敌机
     4                     //
     5                     var enemy = enemies[i];//敌机
     6                     //检测敌机和英雄机是否碰撞
     7                     if ((enemy.y > gameData.HEIGHT)||(enemy.canDelete))
     8                     {
     9                         enemies.splice(i,1);//删除当前超出屏幕的飞机
    10                         continue;
    11                     }
    12                     enemy.paint();//绘制飞机
    13                     if (gameData.state == gameData.RUNNING)
    14                     {//游戏运行中时才移动飞机
    15                         enemy.step();//移动飞机
    16                     }
    17                     //判断是否和我方飞机碰撞
    18                     if (enemy&&enemy.hit(hero))
    19                     {//敌机和我方飞机相撞
    20                             enemy.bang();
    21                             hero.bang();//飞机销毁
    22                     }
    23                     //判断子弹
    24                     for (var j=0; j<bullets.length; j++)
    25                     {//子弹遍历
    26                         var bullet = bullets[j];//子弹
    27                         if (enemy.hit(bullet))
    28                         {//子弹撞机敌方飞机
    29                             enemy.bang();//删除敌机
    30                             bullet.bang();//删除子弹
    31                         }
    32                     }
    33                 }
    34             }
    View Code

    六、主体流程的控制

      这里使用switch来控制在执行相应状态的操作,使用setTimeout来控制循环的进行,感觉setTimeout比setInterval更加的容易控制

     1                 //根据游戏状态执行相应操作
     2                 switch (gameData.state)
     3                 {
     4                     case gameData.START://游戏开始状态
     5                         context.drawImage(startLogo,30,0);//绘制开始logo
     6                         break;
     7                     case gameData.STARTING: //英雄机进场过渡状态
     8                         loading.paint();//绘制飞机入场动画
     9                         loading.step();//入场动画
    10                         break;
    11                     case gameData.RUNNING: //游戏进行状态
    12                         hero.paint();
    13                         hero.step();
    14                         hero.shoot();//飞机射击
    15                         paintBullets();//绘制所有子弹
    16                         clearStep();//清除超出的子弹
    17 
    18                         if (enemyTime%100 == 0)
    19                         {
    20                             createEnemies();//创建敌方飞机
    21                         }
    22                         paintEnemiesAndCheckHit();//绘制所有敌方飞机和碰撞检测
    23                         break;
    24                     case gameData.PAUSED: //游戏暂停状态
    25                         hero.paint();
    26                         paintBullets();//绘制所有子弹
    27                         paintEnemiesAndCheckHit();//绘制所有敌方飞机和碰撞检测
    28                         paintPaused();
    29                         break;
    30                     case gameData.GAMEOVER: //游戏结束状态
    31                         gameover();
    32                         break;
    33                 }
    34                 painText();//绘制得分
    35                 
    36                 //定时器,画布刷新
    37                 setTimeout(function(){
    38                     gameExec();
    39                 },10);
    View Code

    七、响应事件的绑定

      1.开始界面单击鼠标,开始游戏

    1             canvas.onclick = function(){
    2                 if (gameData.state == gameData.START)
    3                 {//在游戏开始状态下单击,进入游戏过渡阶段
    4                     gameData.state = gameData.STARTING;//改变游戏状态
    5                 }
    6             }

       2.绑定鼠标的移动事件,英雄机是跟随鼠标移动的

     1             canvas.onmousemove = function(event){
     2                 //获取鼠标当前相对于canvas画布的坐标
     3                 var x = event.offsetX;
     4                 var y = event.offsetY;
     5                 //我方飞机坐标设置
     6                 hero.x=x-hero.width/2;// x坐标
     7                 hero.y=y-hero.height/2;//y坐标
     8                 if (gameData.state == gameData.PAUSED)
     9                 {
    10                     gameData.state = gameData.RUNNING;
    11                 }
    12             }
    View Code

       3.鼠标离开画布事件,鼠标离开则游戏暂停

    1             canvas.onmouseout = function(){
    2                 if (gameData.state == gameData.RUNNING)
    3                 {
    4                     gameData.state = gameData.PAUSED;
    5                 }
    6             }    
    View Code

    八、后续的一些设想

      现在的游戏不能重新开始,需要刷新才能重新开始,所以定义了 init() 函数用于游戏结束后重新开始(需要删除setTimeout事件):

                function init(){
                    //设置游戏的初始状态
                    gameData.state = gameData.START;
                    gameData.score = 0;//分数重置
                    gameData.heroLife = 3;//声明值重置
                    //游戏运行
                    gameExec();
                }

       还有关于子弹的类型的设想: 可以设置 双列子弹,散花弹等子弹的类型,子弹可升级,设置子弹的威力等;可以设置速度的变更等

      有路过的大神可以看下下边的源码,指点下(源码不长就10kb多点)

    九、源码链接

      完整源码下载

  • 相关阅读:
    体温单时间控件
    搭建Android 开发环境(精华)
    即时通讯
    车牌识别系统
    JSON 生成 C# Model
    Arduino 视频教程
    .Net主线程扑捉子线程中的异常
    用C#操作IIS创建虚拟目录和网站
    C#中简单的this与get的用法(string,decimal)
    c#读取Excel数据到Gridview
  • 原文地址:https://www.cnblogs.com/Medeor/p/4970353.html
Copyright © 2011-2022 走看看