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 }

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

 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             ...

 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 .......

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

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

  继承实例化:

 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);

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

四、英雄机的子弹发射

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

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             }

六、主体流程的控制

  这里使用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);

七、响应事件的绑定

  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             }

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

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

八、后续的一些设想

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

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

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

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

九、源码链接

  完整源码下载

时间: 2024-10-01 02:07:41

web版canvas做飞机大战游戏 总结的相关文章

H5 canvas 实现飞机大战游戏

首先看几张效果图: 上面三张图分别对应游戏的三种状态 ready,play,pause.体验一下 先介绍一下canvas 画图的原理,在这个游戏中的背景,飞机,子弹以及飞机被击中爆炸的效果都是一张张的图片,通过canvas的 drawImage() 函数把这一帧需要的所有图片按其所在的位置(坐标)画到画布上,当然有时候也需要画些文本,比如左上角的得分:然后接着画下一帧,同时改变飞机和子弹的位置:画下一帧之前一定要清除画布(通过这个函数 clearRect(x,  y, width, height

微信飞机大战游戏开发

原文出自:方杰|http://fangjie.sinaapp.com/?p=366转载请注明出处 这学期上了一学期的Windows游戏开发课程,学期末的时候所以决定做一个微信飞机大战的小游戏. 不同于微信手机上的飞机大战,这是一个Win32平台下游戏.Win32项目,VS2008开发平台,利用我的老师写的TinyEngine微型游戏引擎开发. TinyEngine引擎的相关源码及介绍参见:https://github.com/JayFang1993/TinyEngine 飞机大战游戏的相关源码参

基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(下)

在飞机大战游戏开发中遇到的问题和解决方法: 1.在添加菜单时,我要添加一个有背景的菜单,需要在菜单pMenu中添加一个图片精灵,结果编译过了但是运行出错,如下图: 查了很多资料,调试了很长时间,整个人都要崩溃了. 最后发现引擎中CCMenu::itemForTouch函数中有遍历子节点的行为,但是循环中没有判断子节点类型是否为CCMenuItem.如图:码,这样一来,加入到pMenu中的图片精灵被当作菜单项取了出来使用,导致报错.老版本的果然又不完善的地方,整个人都不好了...果断修改引擎里的源

基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(中)

接<基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(上)> 三.代码分析 1.界面初始化 1 bool PlaneWarGame::init() 2 { 3 bool bRet = false; 4 do 5 { 6 CC_BREAK_IF(! CCLayer::init()); 7 8 _size = CCDirector::sharedDirector()->getWinSize(); 9 10 // 设置触摸可用 11 this->setIsTouchEnabled

基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(上)

最近接触过几个版本的cocos2dx,决定每个大变动的版本都尝试一下.本实例模仿微信5.0版本中的飞机大战游戏,如图: 一.工具 1.素材:飞机大战的素材(图片.声音等)来自于网络 2.引擎:cocos2d-1.0.1-x-0.9.2 3.环境:vs2010 二.使用的类 1.游戏菜单界面类:PlaneWarMenu——派生自CCLayer类. 1 // 游戏菜单界面类 2 class PlaneWarMenu: public CCLayer 3 { 4 public: 5 virtual bo

用Swift语言和Sprite Kit复制微信飞机大战游戏

先上GitHub链接: https://github.com/songrotek/PlaneWar.git 接下来稍微讲解一下! 这个程序还有点Bug,见谅! 1 说明 游戏采用了Sprite kit最新的Per pixel for physic 技术,就是直接使用texture纹理作为sprite的physics body . 游戏的texture.atlas从别的打飞机项目中拷之并辛苦地分解了. 游戏编写借鉴了网上的objc代码! 2 游戏编写过程 添加背景-> 添加控制的飞机-> 添加发

用canvas写飞机大战

1.老规矩,当我们开始做项目的时候,我们第一步就是要进行分析,当我们的游戏开始做的时候我们要把一整个游戏分成五个阶段来写: 五个阶段和我方飞机的生命值,还有游戏的得分情况如下: //游戏欢迎状态 const START=0; // 第二阶段:游戏加载状态 const LOADING=1; // 第三阶段:游戏运行状态 const RUNNING=2; // 第四阶段:游戏暂停阶段 const PAUSE=3; // 第五阶段:游戏结束阶段 const GAMEOVER=4; //定义游戏得分 v

飞机大战游戏思路及问题总结

在做这个游戏刚开始时,不知如何着手,思路很乱,不能统观全局.如隔靴搔痒,抓不住其中要点,窥不透真义.几天下来,在老师的引导下,基本完成了简单的功能,现在回顾一下过程中的心得以及遇到的问题,希望有所助益. 一.思路 1.页面布局 - 有两个界面,开始界面和游戏界面,两个大div:开始界面div有开始背景图片,有一个开始按钮,建议按钮包裹在一个div里,方便定位;游戏界面有其背景图片,上面有个得分div,另外还有暂停div包含继续按钮和重新开始按钮以及结果分数. - css div最好都是绝对定位,

cocos2d中分步实现飞机大战----游戏场景中背景的滚动

上一节说了场景的跳转,现在开始布置游戏游戏界面.在游戏的主界面,首先要有游戏背景,为了使GameScene的代码不至于太多,可以吧自己的背景进行封装,在GameScene中调用就好,飞机的正常飞行移动可以用北京的移动来实现.创建BackGround: background.h: #include "cocos2d.h" USING_NS_CC; class background:public Node{ public: CREATE_FUNC(background); bool ini