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

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

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

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

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

  主要包括:

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

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

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

             /*-- 加载游戏图片 -------------------------------------------------------------------*/
//背景图片
var bgImg = new Image();
bgImg.src="data:images/background.png";
//logo图片
var startLogo = new Image();
startLogo.src = "images/start.png";
//加载飞机入场动画
var loadings = [];
loadings[0] = new Image();
loadings[0].src="Images/game_loading1.png";
loadings[1] = new Image();
loadings[1].src="Images/game_loading2.png";
loadings[2] = new Image();
loadings[2].src="Images/game_loading3.png";
loadings[3] = new Image();
loadings[3].src="Images/game_loading4.png";
//加载英雄机图片
var heros = [];
heros[0] = new Image();
heros[0].src="data:images/hero1.png";
heros[1] = new Image();
heros[1].src="data:images/hero2.png";
//英雄机爆破动画图片
heros[2] = new Image();
heros[2].src="data:images/hero_blowup_n1.png";
heros[3] = new Image();
heros[3].src="data:images/hero_blowup_n2.png";
heros[4] = new Image();
heros[4].src="data:images/hero_blowup_n3.png";
heros[5] = new Image();
heros[5].src="data:images/hero_blowup_n4.png";
//加载子弹的图片
var bullet = [];
bullet[0] = new Image();
bullet[0].src = "images/bullet1.png";
...
             /*-- 初始化游戏内容相关数据 --*/
//初始化游戏背景图片数据
var SKY = {
imgs : bgImg,//背景图片
width : 480,//图片宽度
height : 852 //图片高度
}
//初始化英雄机入场动画图片数据
var LOADING = {
imgs : loadings,
width : 186,//图片宽度
height : 38,//图片高度
sum : loadings.length //图片个数
}
//初始化英雄机的数据
var HERO = {
imgs : heros,
width : 99,
height : 124,
sum : heros.length,
length : 2//我方飞机正常图片个数
}
//初始化子弹的数据
var BULLET = {//默认子弹
imgs : bullet,
width : 9,
height : 21,
sum : bullet.length
}
.......

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

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

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

             /*-- 通用构造器对象 前端代码尽量地使用通用代码 -------------------------------------------------------------------------------------------------------*/
function Compant(config){
//加载图片
this.imgs = config.imgs;
//图片的宽度和高度
this.width = config.width;
this.height = config.height;
this.sum = config.sum;
this.length = config.length;
// 敌方飞机具有以下属性
this.type = config.type;//敌机类型
this.life = config.life;//敌机声明值
this.score = config.score;//敌机分数
// 设置相对速度
this.time = 0;
// 设置图片的索引值
this.index = 0;
// 是否执行爆破动画的标识
this.down = false;
// 是否删除标识
this.canDelete = false;
//绘图坐标
this.x = 0;
this.y = 0;
// 绘制方法
this.paint = function(){
context.drawImage(this.imgs[this.index],this.x,this.y);
}
// 移动方法
this.step = function(){}
// 执行撞击后的逻辑方法
this.bang = function(){}
}

  继承实例化:

             //---背景
//创建背景图片的构造器
function BgSky(config){
//调用通用构造器初始化
Compant.call(this,config);
//图片绘制高度变量
this.y1 = -this.height;
this.y2 = 0;
//定义绘制方法
this.paint = function(){
context.drawImage(this.imgs,0,this.y1);//第一张图片
context.drawImage(this.imgs,0,this.y2);//第二张图片
}
//背景heigth运动方法
this.step = function(){
this.time++;
if (this.time%3==0)
{//控制背景图片height值的增加
this.y1++;//图片运动下一帧
this.y2++;
//图片移动处画布后将y坐标重置为-height 实现图片衔接滚动
this.y1>this.height&&(this.y1 = -this.height);
this.y2>this.height&&(this.y2 = -this.height);
this.time=1;//重置移动时间
}
}
}
//创建图片对象
var sky = new BgSky(SKY); //---英雄机入场动画构造器
function Loading(config){
Compant.call(this,config);
//定义绘制
this.paint = function(){
//绘制飞机入场动画图片
context.drawImage(this.imgs[this.index],0,gameData.HEIGHT-this.height);
}
//定义入场动画
this.step = function(){
this.time++;
if (this.time%20==0)
{//实现动画的播放速度
this.index++;//下一帧动画
if (this.index==this.sum)
{//判断动画结束后,更改游戏的状态,进入第三阶段游戏阶段
gameData.state=gameData.RUNNING;
this.time=0;//重置动画时间
}
}
}
}
//创建飞机入场动画的对象
var loading = new Loading(LOADING);

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

四、英雄机的子弹发射

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

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

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

  子弹的绘制:

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

  删除子弹的判断:

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

  

五、敌机的相关设置

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

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

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

             function paintEnemiesAndCheckHit(){
for (var i=0; i<enemies.length; i++)
{//遍历敌机
//
var enemy = enemies[i];//敌机
//检测敌机和英雄机是否碰撞
if ((enemy.y > gameData.HEIGHT)||(enemy.canDelete))
{
enemies.splice(i,1);//删除当前超出屏幕的飞机
continue;
}
enemy.paint();//绘制飞机
if (gameData.state == gameData.RUNNING)
{//游戏运行中时才移动飞机
enemy.step();//移动飞机
}
//判断是否和我方飞机碰撞
if (enemy&&enemy.hit(hero))
{//敌机和我方飞机相撞
enemy.bang();
hero.bang();//飞机销毁
}
//判断子弹
for (var j=0; j<bullets.length; j++)
{//子弹遍历
var bullet = bullets[j];//子弹
if (enemy.hit(bullet))
{//子弹撞机敌方飞机
enemy.bang();//删除敌机
bullet.bang();//删除子弹
}
}
}
}

六、主体流程的控制

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

                 //根据游戏状态执行相应操作
switch (gameData.state)
{
case gameData.START://游戏开始状态
context.drawImage(startLogo,30,0);//绘制开始logo
break;
case gameData.STARTING: //英雄机进场过渡状态
loading.paint();//绘制飞机入场动画
loading.step();//入场动画
break;
case gameData.RUNNING: //游戏进行状态
hero.paint();
hero.step();
hero.shoot();//飞机射击
paintBullets();//绘制所有子弹
clearStep();//清除超出的子弹 if (enemyTime%100 == 0)
{
createEnemies();//创建敌方飞机
}
paintEnemiesAndCheckHit();//绘制所有敌方飞机和碰撞检测
break;
case gameData.PAUSED: //游戏暂停状态
hero.paint();
paintBullets();//绘制所有子弹
paintEnemiesAndCheckHit();//绘制所有敌方飞机和碰撞检测
paintPaused();
break;
case gameData.GAMEOVER: //游戏结束状态
gameover();
break;
}
painText();//绘制得分 //定时器,画布刷新
setTimeout(function(){
gameExec();
},10);

七、响应事件的绑定

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

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

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

             canvas.onmousemove = function(event){
//获取鼠标当前相对于canvas画布的坐标
var x = event.offsetX;
var y = event.offsetY;
//我方飞机坐标设置
hero.x=x-hero.width/2;// x坐标
hero.y=y-hero.height/2;//y坐标
if (gameData.state == gameData.PAUSED)
{
gameData.state = gameData.RUNNING;
}
}

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

             canvas.onmouseout = function(){
if (gameData.state == gameData.RUNNING)
{
gameData.state = gameData.PAUSED;
}
}

八、后续的一些设想

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

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

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

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

九、源码链接

  完整源码下载

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

  1. Canvas:飞机大战 -- 游戏制作

    Canvas:飞机大战 最开始我们要初始化信息,我们有五个状态:游戏封面,加载状态,运行状态,游戏暂停,游戏结束. 我们还需要  得分--score,生命--life. var START = 1;/ ...

  2. H5 canvas 实现飞机大战游戏

    首先看几张效果图: 上面三张图分别对应游戏的三种状态 ready,play,pause.体验一下 先介绍一下canvas 画图的原理,在这个游戏中的背景,飞机,子弹以及飞机被击中爆炸的效果都是一张张的 ...

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

    在飞机大战游戏开发中遇到的问题和解决方法: 1.在添加菜单时,我要添加一个有背景的菜单,需要在菜单pMenu中添加一个图片精灵,结果编译过了但是运行出错,如下图: 查了很多资料,调试了很长时间,整个人 ...

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

    接<基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(上)> 三.代码分析 1.界面初始化 bool PlaneWarGame::init() { bool bRet = fals ...

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

    最近接触过几个版本的cocos2dx,决定每个大变动的版本都尝试一下.本实例模仿微信5.0版本中的飞机大战游戏,如图: 一.工具 1.素材:飞机大战的素材(图片.声音等)来自于网络 2.引擎:coco ...

  6. 11.pygame飞机大战游戏整体代码

    主程序 # -*- coding: utf-8 -*- # @Time: 2022/5/20 22:26 # @Author: LiQi # @Describe: 主程序 import pygame ...

  7. canvas绘制“飞机大战”小游戏,真香!

    canvas是ArkUI开发框架里的画布组件,常用于自定义绘制图形.因为其轻量.灵活.高效等优点,被广泛应用于UI界面开发中. 本期,我们将为大家介绍canvas组件的使用. 一.canvas介绍 1 ...

  8. 一、利用Python编写飞机大战游戏-面向对象设计思想

    相信大家看到过网上很多关于飞机大战的项目,但是对其中的模块方法,以及使用和游戏工作原理都不了解,看的也是一脸懵逼,根本看不下去.下面我做个详细讲解,在做此游戏需要用到pygame模块,所以这一章先进行 ...

  9. 用Javascript模拟微信飞机大战游戏

    最近微信的飞机大战非常流行,下载量非常高. 利用JS进行模拟制作了一个简单的飞机大战[此源码有很多地方可以进行重构和优化] [此游戏中没有使用HTML5 任何浏览器都可以运行]. 效果图: 原理:利用 ...

随机推荐

  1. 第三次寒假作业 sketch 了解

    什么是sketch? sketch 是一种基于散列的数据结构,可以在高速网络环境中,实时地存储流量特征信息,只占用较小的空间资源,并且具备在理论上可证明的估计精度与内存的平衡特性. 通过设置散列函数, ...

  2. unity像素贪吃蛇

    [ 星 辰 · 别 礼 ] 设计过程: 首先,在之前玩坏控制台做的那个c#贪吃蛇之后,我以为做unity会很简单,但事实比较不如人意...拖了好几天.因为过程中遇到一些问题 蛇身的移动,还是用列表,将 ...

  3. 福大软工1816:Alpha(10/10)

    Alpha 冲刺 (10/10) 队名:第三视角 组长博客链接 本次作业链接 团队部分 团队燃尽图 工作情况汇报 张扬(组长) 过去两天完成了哪些任务: 文字/口头描述: 1.和愈明.韫月一起对接 2 ...

  4. TCP 的有限状态机

    TCP 有限状态机的图中每一个方框都是 TCP 可能具有的状态. 每个方框中的大写英文字符串是 TCP 标准所使用的 TCP 连接状态名. 状态之间的箭头表示可能发生的状态变迁. 箭头旁边的字,表明引 ...

  5. Deeplearning——Logistics回归

    资料来源:1.博客:http://binweber.top/2017/09/12/deep_learning_1/#more——转载,修改更新 2.文章:https://www.qcloud.com/ ...

  6. python Django框架接入微信公众平台

    1.在接入微信公众平台之前,需要在微信公众平台配置好基本信息,如下: 这个时候点击“提交”按钮,会提示“Token校验失败”,不要着急,这是必然会出现的现象,先不要退出页面,保留各项输入的数据,按第二 ...

  7. Matlab 中的varargin/nargin varargout/nargout

    Varargin = var+ arg+ in = variable length(可变长) input argument(输入参数) list(列表) :允许调用该函数时根据需要改变输入参数的个数 ...

  8. HTML5 Web SQL 数据库总结

    Web SQL 数据库 API 并不是 HTML5 规范的一部分,但是它是一个独立的规范,引入了一组使用 SQL 操作客户端数据库的 APIs. 如果你是一个 Web 后端程序员,应该很容易理解 SQ ...

  9. Elasticsearch query和filter的区别

    1.关于Query context和filter context 查询语句的表现行为取决于使用了查询上下文方式还是过滤上下文方式. Query context:查询上下文,回答了“文档是如何被查询语句 ...

  10. 【题解】HNOI2014世界树

    脑子不清醒的时候千万别写题.写题写不下去了千万别死扛,重构才是你唯一的出路QAQ 昨天很想快点写道题,思路没有很清晰的时候就写了,结果……今天一怒之下决定重整思路重构代码,其实不过是半个小时的事情…… ...