唠唠:两天的时间跟着做了个飞机大战的游戏,感觉做游戏挺好的。说是用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. 福大软工1816:Alpha(6/10)

    Alpha 冲刺 (6/10) 队名:第三视角 组长博客链接 本次作业链接 团队部分 团队燃尽图 工作情况汇报 张扬(组长) 过去两天完成了哪些任务: 文字/口头描述: 1.组织会议 2.帮助队员解决 ...

  2. 【redis数据库学习】用JAVA连接redis数据库各种报错

    最近项目中,需要用到redis数据库,然后使用Jedis让JAVA连接redis. 首先,安装redis数据库,参考的是:http://www.runoob.com/redis/redis-insta ...

  3. 原生js操作Dom节点:CRUD

    知识点,依然会遗忘.我在思考到底是什么原因.想到研究生考试准备的那段岁月,想到知识体系的建立,知识体系分为正向知识体系和逆向知识体系:正向知识体系可以理解为教科书目录,逆向知识体系可以理解考试真题. ...

  4. exception = {"元数据集合中已存在具有标识“xxx”的项。\r\n参数名: item"}

    vs提示:exception = {"元数据集合中已存在具有标识"xxx"的项.\r\n参数名: item"} 出现这个错误说明有重复的字段,有可能是继承的类里 ...

  5. windows批处理学习(call与start)---02

    参考:https://www.cnblogs.com/Braveliu/p/5078283.html 一.call命令总结 (1)call命令简介 语法: call [ [Drive:] [Path] ...

  6. 安装django 提示ImportError: No module named setuptools

    安装django前要先安装setuptools 先安装一些必要的包,否则会报错:Python build finished, but the necessary bits to build these ...

  7. 细说匿名内部类引用方法局部变量时为什么需要声明为final

    一.前言 在研究公司某个项目的源码,看到前人使用了挺多内部类,内部类平时我用的比较多的是匿名内部类,平时用的多的是匿名内部类,其他形式的用的比较少,然后我就有个疑惑:到底内部类是基于什么样的考虑,才让 ...

  8. asp.net MVC4 @Html.DropDownList的使用

    在MVC4中使用Razor语法,一使用就爱上他了, 一般项目都是有一些增删改查功能,表单下拉框是经常使用的,除了用原始的<select>外,还可以用@Html.DropDownList和@ ...

  9. set类型没有单独取值功能 通过循环取值

    set类型没有单独取值功能 通过循环取值

  10. Oracle数据库表被锁定以及去除方式

    select t2.username, t2.sid, t2.serial#, t3.object_name, t2.OSUSER, t2.MACHINE, t2.PROGRAM, t2.LOGON_ ...