您现在的位置: 万盛学电脑网 >> 程序编程 >> 脚本专题 >> javascript >> 正文

打灰机是怎样炼成的

作者:佚名    责任编辑:admin    更新时间:2022-06-22

   游戏循环:

  每一个游戏都是由获得用户输入,更新游戏状态,处理AI,播放音乐,还有画面显示这些行为组成。游戏主循环就是用来处理这个行为序列的。

  所以首先我们最基本的就是创建一个游戏主循环。对于javascript来说,实现这个游戏循环只有setTimeout和setInterval 这两个方法可选了。

  那到底是setTimeout好还是setInterval 好呢。其实毫无疑问的,setTimeout比较好。setTimeout是在设定的时间后执行一次指定方法,而setInterval是每隔一定的时间久执行指定方法。可能很多人会存在疑问,这样不是setInterval更好吗,直接就可以实现循环了,setTimeout还要用递归实现循环。没错,setInterval实现循环更简单,但是却不是更好。

  因为:

  无论是setTimeout还是setInterval,触发时,如果当前进程不为空,都得去排队等待执行,这一点上是无差异的。

  区别是,setTimeout只需排一次队,setInterval则需要按照预设的间隔时间,每到时间点都去排一下。

  setInterval去排队时,如果发现自己还在队列中未执行,则会被drop掉。也就是说,同一个Interval,在队列里只会有一个。

  因为队列机制,无论是setTimeout还是setInterval,第一次触发时的时间,只会等于大于预设时间,不可能小于。

  对于setInterval来说,如果执行时间大于预设间隔时间,很可能导致连续执行,中间没有时间间隔,这是很糟糕的,很可能会耗费大量cpu。

  所以对于动画来说,如果单帧的执行时间大于间隔时间,用setTimeout比用setInterval更保险。

  于是利用setTimeout这样实现了游戏循环:

1 setTimeout(function(){  2 //循环体 3  setTimeout(arguments.callee, 10);  4 },10);

  不过,真的这样简单吗?要知道javascript是单线程的,当要处理的事务比较多时,setTimeout的执行时间根本得不到保证,这样在不同性能的浏览器上就会有不同的表现了。这时我们可以利用时间差来控制循环体的执行时间。

01 var _last = new Date().getTime(); 02    03 setTimeout(function(){ 04    05 var _now = new Date().getTime(); 06    07 if(_now - _last > delay){ 08    09 _last = _now; 10    11 //循环体… 12    13 } 14    15 setTimeout(arguments.callee, 10); 16    17 },10);

  这样,循环体执行的时间间隔就比较精准了。

  游戏帧:

  游戏循环有了,现在我们要明确的就是每个循环里要做些什么了。这里的每个循环就是我们所说的帧了。在我们的打灰机游戏里每一帧要做的事情无非就是下面这些 :

  移动敌机

  移动子弹

  碰撞检测

  游戏结束检测

  补充敌机

  移动敌机和子弹只要在当前的位置上加上当前的速度变量就可以了,比较简单。

  我重点说说做碰撞检测。

  碰撞检测:

  打灰机游戏里的碰撞检测主要是检测子弹和敌机,敌机和玩家灰机的碰撞。在这里我们只做简单的矩形碰撞检测。在dom的世界全是方方块块的东东,至于飞机的形状,我想说 不要在意这些细节。要知道,我们是在用javascript做游戏,还得兼容该死的IE6,性能才是最重要的。忽略灰机的形状,这样碰撞检测就简单了,只要根据两个dom元素的位置和长宽判断是否有重叠就可以了。不过更简单的是,直接使用YUI里面的inRegion方法就可以了,哈哈。

  既然如此简单,兴高采烈的开始代码了。开开心心的写个for循环,对每一架敌机和子弹做碰撞检测,然后对每一架敌机和玩家灰机做碰撞检测。大功告成,迫不及待的运行观看效果,然后小伙伴们都惊呆了!chrome下灰机机卡得一顿一顿的,而IE6直接罢工了有木有!我还是高估了javascript的性能,当务之急是对碰撞检测的性能做个优化。

  性能优化:

  每一屏内有十几架飞机,子弹和玩家灰机都分别和敌机做碰撞检测,则每一帧内要做上百次碰撞检测。如果只对可能发生碰撞的进行检测,每一帧的碰撞检测可以减少到十次以内。但是怎么知道哪些灰机是可能发出碰撞的呢。如果敌机可以出现在任意的位置上,那肯定是没办法做到的。所以只好把敌机固定在不同的航线上。如下图所示,

打灰机是怎样炼成的  三联

  把游戏区域根据敌机的宽度划分成一条条固定的航线,敌机会随机出现在其中的一条航线上。于是,用子弹的x坐标除以敌机的宽度计算出子弹所处的航线,子弹只要和它所处的航线上的敌机作碰撞检测就可以了。

  如果整个游戏区域分成10条航线