2014-7-29 18:36| 发布者: tianzc| 查看: 199| 评论: 0
作者:yulonh; 2012年加入腾讯公司,喜爱新鲜事物及新技术,热衷于利用技术提升用户体验,目前负责财付通运营活动的前端开发工作。
想必大家都打完灰机了,现在想不想知道打灰机是怎么实现的呢?且容我抽丝剥茧,娓娓道来~~ 游戏循环: 每一个游戏都是由获得用户输入,更新游戏状态,处理AI,播放音乐,还有画面显示这些行为组成。游戏主循环就是用来处理这个行为序列的。 所以首先我们最基本的就是创建一个游戏主循环。对于javascript来说,实现这个游戏循环只有setTimeout和setInterval 这两个方法可选了。 那到底是setTimeout好还是setInterval 好呢。其实毫无疑问的,setTimeout比较好。setTimeout是在设定的时间后执行一次指定方法,而setInterval是每隔一定的时间久执行指定方法。可能很多人会存在疑问,这样不是setInterval更好吗,直接就可以实现循环了,setTimeout还要用递归实现循环。没错,setInterval实现循环更简单,但是却不是更好。 因为:
所以对于动画来说,如果单帧的执行时间大于间隔时间,用setTimeout比用setInterval更保险。 于是利用setTimeout这样实现了游戏循环:
不过,真的这样简单吗?要知道javascript是单线程的,当要处理的事务比较多时,setTimeout的执行时间根本得不到保证,这样在不同性能的浏览器上就会有不同的表现了。这时我们可以利用时间差来控制循环体的执行时间。
这样,循环体执行的时间间隔就比较精准了。 游戏帧:
移动敌机和子弹只要在当前的位置上加上当前的速度变量就可以了,比较简单。 我重点说说做碰撞检测。 碰撞检测: 打灰机游戏里的碰撞检测主要是检测子弹和敌机,敌机和玩家灰机的碰撞。在这里我们只做简单的矩形碰撞检测。在dom的世界全是方方块块的东东,至于飞机的形状,我想说不要在意这些细节。要知道,我们是在用javascript做游戏,还得兼容该死的IE6,性能才是最重要的。忽略灰机的形状,这样碰撞检测就简单了,只要根据两个dom元素的位置和长宽判断是否有重叠就可以了。不过更简单的是,直接使用YUI里面的inRegion方法就可以了,哈哈。
既然如此简单,兴高采烈的开始代码了。开开心心的写个for循环,对每一架敌机和子弹做碰撞检测,然后对每一架敌机和玩家灰机做碰撞检测。大功告成,迫不及待的运行观看效果,然后小伙伴们都惊呆了!chrome下灰机机卡得一顿一顿的,而IE6直接罢工了有木有!我还是高估了javascript的性能,当务之急是对碰撞检测的性能做个优化。 性能优化: 每一屏内有十几架飞机,子弹和玩家灰机都分别和敌机做碰撞检测,则每一帧内要做上百次碰撞检测。如果只对可能发生碰撞的进行检测,每一帧的碰撞检测可以减少到十次以内。但是怎么知道哪些灰机是可能发出碰撞的呢。如果敌机可以出现在任意的位置上,那肯定是没办法做到的。所以只好把敌机固定在不同的航线上。如下图所示,
把游戏区域根据敌机的宽度划分成一条条固定的航线,敌机会随机出现在其中的一条航线上。于是,用子弹的x坐标除以敌机的宽度计算出子弹所处的航线,子弹只要和它所处的航线上的敌机作碰撞检测就可以了。 如果整个游戏区域分成10条航线,性能就提升了10倍!!同理,对于敌机和玩家灰机的检测也是如此处理。如此,性能提升20倍!! 操作优化: 实现玩家灰机的方向控制也是比较简单的,检测键盘事件的上下左右按键事件,对玩家灰机的x,y坐标做相应的增减即可。 但是在游戏中我们会发现玩家灰机的移动很不流畅,如果把移动速度增大,则会出现一跳一跳的感觉,如果移动速度变小玩家灰机的移动却很慢。这是因为键盘的事件响应频率太慢,所以只要提高移动控制的频率就可以解决这个问题了。类似上文所说的游戏循环,我们可以创建一个专门控制玩家灰机的移动的循环体,在循环体内不停检测标志位direction的值,根据direction的控制玩家灰机的移动方向。而在键盘响应事件中依据玩家按下的键对direction赋予不同的值,其中direction的值0表示静止,1表示向上移动,2表示向下移动,3表示向左移动,4表示向右移动。 实现代码如下: 现在玩家灰机的移动控制就流畅很多了。 一款简单的打灰机游戏就这样炼成啦,最后我们再去打一把灰机吧。 |