cocos2d-js schedule定时器误差解决办法

 cocos2d-js提供的定时器是有误差的,这会导致游戏的一些逻辑判断出现问题。下面的代码是一个实验,验证一下schedule循环执行的时间误差:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var  deviationTestLayer = cc.Layer.extend({
     ctor: function (){
         this ._super();
         //获取初始时间
         var  startTime =  new  Date().getTime();
         var  count = 0;
         //执行定时任务 没0.1s执行一次
         this .schedule( function (){
             var  timePass =  new  Date().getTime() - startTime;
             count++;
             var  delta = timePass - count*100;
             console.log( "timePass=" +timePass + ", total delta=" +delta+ ", count=" +count);
         },0.1);
     }
});

    上面的代码定时器回调函数记录了当前运行时间timePass,误差delta,运行次数count。

    下面是在chrome浏览器运行部分截图:

timepass.jpg

    可以发现随着count越来越大,delta误差(和当前运行环境,机器性能,频帧有关)也越来越大。理论上应该执行159次,实际执行了152次!

    Cocos2d-js自带的定时器为什么会越走越慢,究其原因,其实schedule是受频帧驱动的,Cocos2d-js框架在每帧的计算中都会遍历全部的定时器,如果此时某个定时器到了触发的时间,则触发这个定时器,框架忽略了定时器周期和帧周期的差距问题,这会导致多次循环之后误差越来越大,甚至漏执行。在一般的游戏开发中,也许没什么影响,那如果在对时间要求很高的游戏中,那如何解决这个问题呢,下面我们来一起优化一下Cocos2d-Js的定时器,实现一个不变慢定时器,请看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mySchedule: function (callbanck,interval){
     var  then = Date.now();
     console.log(then);
     //用户设定的时间间隔,单位:秒(S)
     interval = interval*1000;
     //bind 传参数this
     this .schedule( function (){
         var  now = Date.now();
         var  delta = now - then;
         if (delta>interval){
             then = now - (delta%interval);
             callbanck.call( this );
         }
     }.bind( this ),0);   //此处的0表示每帧都触发
}

    mySchedule和cocos2d-js提供的schedule使用方法一样,实现依赖于schedule方法,mySchedule让schedule每帧都触发,也就是游戏的最小时间间隔。在每帧触发的时候,判断当前时间和上一次的时间间隔delta,如果delta超过了用户设定的interval值,则触发用户的回调函数。

其中代码 then = now - (delta%interval)是实现不变慢定时器的关键点,在cocos2d-js中是用then = now。

    举个例子说明:假设用户设定interval = 0.1s 也就是100ms触发一次,频帧60fps,每16ms触发一次mySchedule的计算,计算可得16x7=112>100,也就是说,需要112ms才实际出发了用户设定的回调函数,比设定的100ms晚了12ms。而delta%interval是本次出发的误差,为了解决误差就要让then = now - (delta%interval),来达到抵消误差目的。

    测试一下新的定时器,是否能达到我们想要的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
var  deviationTestLayer = cc.Layer.extend({
     ctor: function (){
         this ._super();
         //获取初始时间
         var  startTime =  new  Date().getTime();
         var  count = 0;
         //执行定时任务 没0.1s执行一次
         this .mySchedule( function (){
             var  timePass =  new  Date().getTime() - startTime;
             count++;
             var  delta = timePass - count*100;
             console.log( "timePass=" +timePass + ", total delta=" +delta+ ", count=" +count);
         },0.1);
         this .scheduleUpdate();
     },
     mySchedule: function (callbanck,interval){
         var  then = Date.now();
         console.log(then);
         interval = interval*1000;
         //bind 传参数this
         this .schedule( function (){
             var  now = Date.now();
             var  delta = now - then;
             if (delta>interval){
                 then = now - (delta%interval);
                 callbanck.call( this );
             }
         }.bind( this ),0);   //此处的0表示每帧都触发
     },
     //在update函数中做大量计算,模拟低频帧的情况
     update: function (){
         for ( var  i=0; i<1000000; i++){
             var  b = 1/0.22222;
         }
     }
});

下面是相同环境下运行结果:

better.png

    误差一直保持在11-13ms之间,并没有变慢,而且执行次数也和理论次数一致!优化定时器成功!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值