`

多timer管理实例-八音盒

 
阅读更多

from http://bbs.9ria.com/forum.php?mod=viewthread&tid=46386

 

多timer管理实例-八音盒

在一些游戏项目中我们经常会用到数量众多的timer或者setInterval和setTimeout。那么如果要实现一些比如暂停之类的功能就会牵涉到timer的管理问题上。
  之前也有一些朋友在论坛提出对这方面知识的询问,通过悬赏也引出了不少高手的多timer管理的实例。比如单timer实现多timer效果的,还有 多timer统一管理的等等。其中大家比较关心的也是比较被选用的可能就是单timer实现多timer效果的。其中有人提到了最小堆管理方法,也有直接 用时间比对的方法。在这里我向大家介绍一种本人设计的一种类类似八音盒原理的管理方法。

  相信大家都知道八音盒的运作原理,就是在一根滚动的柱子上根据击打的节奏和音符所在序位刻下凹槽或者制造突起。然后当这些凹槽或者凸起经过不同长度拨 片的时候发出对应的声音。其原理和计算机的0101 加指针很有相似之处。那么在一个制作完成的八音盒里就是N个音符按照自己的时间间隔来执行发声,这和timer管理中函数根据自身间隔执行程序是类似的。 那么我们也可以将程序做成八音盒的结构,一个索引指针表示现在滚柱正经过拨片的地方,一个数组序列表示滚柱上的凹曹和序号,然后用一个timer来做驱动 滚柱转动的动力。然后我们只要根据需要在数组了记录下函数触发的间隔和序号就可以象八音盒那样正常工作了。

  这个时候有人会问,模拟这个结构和其他的管理方法有什么区别?这么做有什么好处吗?
  我的思考是这样的:其他的多timer管理或者模拟都需要根据当前的timer心跳也就是时间去逐个比对哪个程序该触发了哪个程序不该触发了,方法有两种:
  第一种是逐个去把间隔时间减少,当间隔时间小于等于0的时候触发函数并且把时间间隔重置为函数间隔时间。
  第二种则是用当前的心跳时间去求余,也就是time %间隔时间,当余为0的时候执行函数。

  两种方式都必须根据timer的数量做数学运算,如果有10000个timer就要做10000次取值+减法+赋值+判断,或者做10000次取值+ 求余+判断。Timer的数量小还好,数量一大势必成为巨大的负担,特别是我们为了追求精确往往把心跳timer的时间间隔设置的尽量小。比如new Timer(1),让他能跑多快跑多快,那么这些数学运算和判断就会有多快就跑多多了。

  那么有什么办法可以避免每次心跳都去做如此多次的运算吗?如何把运算次数降到最小?这时我想到了,如果每 次心跳去驱动一个指针,而这个指针指向的一个数组的指针位置能读出我这次心跳应该执行的函数就好了。这样1000个timer也只是一次心条去取 10000次值而已,免计算免判断直接运行。那么这个数组该怎么生成呢?在新的timer被添加进来的时候我们可以得到他所请求的时间间隔,我们可以根据 现下所已经有的timer的间隔来建立这张表,而这张表的完整长度就是所有间隔时间的最小公倍数。

  比如我们有3个timer间隔分别为2、3、4毫秒,那么生成一张长度为2、3、4的最小公倍数长度12的数组,数组索引代表时间12毫秒为一个循 环,每次心跳只要计算出指针在这个数组中的位置即可,而每位中则保存该时间需要触发的函数在函数表里的索引号即可。那么每次得到指针后就可以以直接取值的 方式来获取和执行函数了。
如下图:



 

那么以这个例子来说一个12长度的数组就可以解决正确间隔判断问题而避免了多次的数学计算和判断。但是到这里并没有结束,请继续往下看。
  看到这,大家都认为可以以生成最小公倍数长度的列表来避免过多的运算了。但是实际并非如此,比如一个比较极端的例子,我只有2个timer,但是一个 间隔是 1 一个间隔是1000000000000毫秒。这会造成什么? 最小公倍数是1000000000000,我们按上面的方法生成的列表长度将是1000000000000。或者我有10000个timer间隔是1到 10000不等,可想而知生成的列表有多长花在生成列表上的时间有多多。那么这里生成一张完整的列表的想法就被否定掉了。于是我想到的则是生成一张局部 的,根据当前时间后的部分列表当列表被消耗完后清空数组继续生成。这样在大部分时间里我们仍然是以完整列表的方式在运行,只在列表消耗完的时候需要临时额 外消耗一些时间来生成一张列表。这就像开火车没路了临时铺一段铁轨然后再开没路了继续铺。而且这样做有另外一个好处,就是在有新的timer被加入进来的 时候生成列表也不会太消耗时间,只是舍弃当前在使用的一小段列表重新生成一小段而不是舍弃整张列重新表生成整张列表。这给多timer管理的灵活性加了保 证。

  有了目标我们就要考虑生成这一段列表的长度应该以什么为标准?固定长度?可以。但是这里我自己采用的是生成列表消耗时间来判断长度。程序中我用了 while(getTimer() – oldTime < 5){}来判断是否继续生成列表。意思就是在生成函数开始后5毫秒之内能生成多少就是多少,时间一到就宣告临时路段修建完成。好处是避免在timer数量 过多的时候导致消耗过多时间。比如只有10个timer可能5毫秒可以声称长达15秒的列表也就是15000长。而10000个timer的时候则只能生 成40到50毫秒的列表。保证不会因为生成列表而导致整个程序拖慢。特别是timer少的时候能保证最优效率,1X秒多执行个5毫秒的计算几乎可以忽略不 计。

  文章写到这里基本阐述了本多timer管理的实现原理和机制。最后放上源代码,方便暂时无法理解和自行编写的朋友们使用。Lii.fla里是一个10000个空timer的测试,有兴趣的朋友可以和官方的进行一下比较。

 

 

  • 大小: 106.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics