在做这个游戏刚开始时,不知如何着手,思路很乱,不能统观全局.如隔靴搔痒,抓不住其中要点,窥不透真义.几天下来,在老师的引导下,基本完成了简单的功能,现在回顾一下过程中的心得以及遇到的问题,希望有所助益.
一.思路
1.页面布局
- 有两个界面,开始界面和游戏界面,两个大div:开始界面div有开始背景图片,有一个开始按钮,建议按钮包裹在一个div里,方便定位;游戏界面有其背景图片,上面有个得分div,另外还有暂停div包含继续按钮和重新开始按钮以及结果分数.
- css div最好都是绝对定位,方便以后获取坐标,两个大div外可用一个div包裹,这个div无需设置宽高,只需绝对定位即可,当然也可以不用外包裹.
- 开始界面和游戏界面div宽高一致,游戏界面设置display为none,其中的暂停div也需要设置隐藏.
基本的布局就完成了,其他样式按自己喜好设置即可.
2.javascript实现
- 游戏界面有我方飞机,子弹还有敌机,这在开始按钮点击之前就应该准备好.这就需要构造函数,封装方法.创建飞机类,属性有图片路径,爆炸图片路径,图片宽高,坐标,分数还有血量,
- 敌机对象继承了飞机函数的属性,多加一个移动属性
- 子弹属性类似敌机,都是随机产生
- 构造完成
- 生成我方飞机对象
- 创建让鼠标位置始终处于我方飞机的中心点函数:
myPlane.imageNode.style.left = cx - MYPLANE_WIDTH/2 + "px"; myPlane.imageNode.style.top = cy - MYPLANE_HEIGTHT/2 + "px";
为避免飞机越界,需判断出现,cx,cy的位置
- 写定时器里的方法
- 背景图片向下移动:改变它的Y坐标值,直到完全跑出div,设置Y为0,循环往复.` mainDiv.style.backgroundPosition = "0px " + bgPositionY + "px";`
- 子弹生成:当我方飞机状态为真时,将生产的子弹对象放进数组里,方便遍历和销毁,子弹生成速度可自行设置
- 子弹移动销毁:遍历数组,调用移动方法,当子弹top值超过一定值,移除子弹图片节点,并把对应的对象从数组移除,因为移除后,数组下标会改变,需要让下标-1
- 敌机生成和移动:类子弹,不同的是敌机有3种,需要设置敌机的生成速度,另外敌机生成位置是随机,需要用到Maths.random();
- 敌机销毁:两种情况:1.top值超出边界,2.敌机与子弹碰撞后,又延迟爆炸时间
- 碰撞:敌机和我方本机碰撞,游戏结束,弹出重新开始框,遍历敌机数组判断top和left值是否相等,是则更换本方飞机图片为爆炸图片,更改本方飞机状态,清除定时器,弹出暂停div,但是继续按钮禁用
- 碰撞:子弹和敌机碰撞后销毁敌机,并计算分数,遍历子弹和敌机数组,敌机血量减少为0,计分,更换敌方飞机图片为爆炸图片,更改敌机状态,移除子弹,中断遍历.
- 开始按钮点击显示游戏界面,开启定时器:隐藏开始界面,显示游戏界面,开启定时器
- 解决IE兼容性方法
function add(obj,type,fn){ if(document.attachEvent){ obj.attachEvent( "on" + type ,fn); }else if(document.addEventListener){ obj.addEventListener(type,fn,false); } } function remove(obj,type,fn){ if(document.detachEvent){ obj.detachEvent( "on" + type ,fn); }else if(document.removeEventListener){ obj.removeEventListener(type,fn,false); } }
- 创建点击游戏界面暂停并弹出继续框函数
- 创建点击继续按钮继续当前游戏函数:要阻止事件流ev.stopPropagation();
- 添加事件
add(mainDiv,"mousemove",mouseMove);//添加鼠标移动事件
add(mainDiv,"click",mainClick);//添加鼠标点击div后暂停事件
add(continueBtn,"click",conClick);//添加继续按钮点击事件
- 重来按钮点击刷新界面,回到开始界面`window.location.reload();`
二.一些问题
1.敌机,特别是大飞机在产生后会闪动,而且一晃就消失了?
原因:帧数.
- 帧数就是在1秒钟时间里传输的图片的量,也可以理解为图形处理器每秒钟能够刷新几次,通常用fps(Frames Per Second)表示。每一帧都是静止的图象,快速连续地显示帧便形成了运动的假象。高的帧率可以得到更流畅、更逼真的动画。帧数 (fps) 越高,所显示的动作就会越流畅。 但是文件大小会变大。
- 游戏帧数:游戏运行时每秒所运行的帧数(简称FPS,Frames Per Second) 和视频一样,FPS越大,在屏幕上的视频就越来越平滑,直到一个临界点(大约是100FPS),超过这个临界点,再高的FPS都只是一个令人惊奇的数值,400FPS和100FPS在人的视觉中几乎没有差别。一般游戏都是40左右fps就可以称之为流畅了。
- 30帧的情况下,每帧显示33ms,响应极限大概是100ms。60帧的情况下,每帧显示16ms,响应极限大概是50ms。
- 我当时设置的定时器的时间是100ms,大飞机生成速度我又设置的比其它飞机慢,就明显看到闪动
- 大部分电影帧数只有 24 帧每秒,就可以流畅
2.事件流影响
function conClick(e){ var ev = e || window.event; pauseDiv.style.display = "none"; myPlane.imageNode.style.display = "block"; ev.stopPropagation(); add(mainDiv,"mousemove",mouseMove); endTimer = window.setInterval(main_loop, 16); }
在创建继续按钮点击事件时,我没有阻止事件流, ` pauseDiv.style.display = "none";`这句话的效果一直没有实现,但是定时器却成功启动了,一直不知为何,后来想原来是,我用的是冒泡法,继续按钮是在pauseDiv里,pauseDiv又处在mainDiv里,而mainDiv正好也有个点击事件,不阻止事件流,就会向外传播,触发mainDiv的点击事件,导致无法隐藏pauseDiv.
function conClick(e){ var ev = e || window.event; pauseDiv.style.display = "none"; myPlane.imageNode.style.display = "block"; ev.stopPropagation(); add(mainDiv,"mousemove",mouseMove); endTimer = window.setInterval(main_loop, 16); }
在创建继续按钮点击事件时,我没有阻止事件流, ` pauseDiv.style.display = "none";`这句话的效果一直没有实现,但是定时器却成功启动了,一直不知为何,后来想原来是,我用的是冒泡法,继续按钮是在pauseDiv里,pauseDiv又处在mainDiv里,而mainDiv正好也有个点击事件,不阻止事件流,就会向外传播,触发mainDiv的点击事件,导致无法隐藏pauseDiv.
function mainClick(){ clearInterval(endTimer); myPlane.imageNode.style.display = "none"; pauseDiv.style.display = "block"; remove(mainDiv,"mousemove",mouseMove); }
3.经过这个项目,才发现构造对象,封装方法很重要,而且也很方便.
4.多定义常量,尽量少用数字,即magic number
- 在源代码编写中,有这么一种情况:编码者在写源代码的时候,使用了一个数字,比如0x2123,0.021f等,他当时是明白这个数字的意思的,但是别的程序员看他的代码,可能很难理解,甚至,过了一段时间,代码的作者自己再看代码的时候也忘记了这个数字代表的含义。
- 在编程中使用幻数是不好的习惯,开发中应当尽量避免
- 代码可读性差,修改不方便
- 解决魔术数字的方法主要是将这些数字定义为常量,或者枚举类型,或者使用编译器的宏定义(如C/C++的#define)