cocos2d-js schedule定时器误差解决办法_cocos 切到后台后 定时器错乱_DongEnLai_CodeNice的博客-程序员秘密

技术标签: Cocos2dx-js  

 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之间,并没有变慢,而且执行次数也和理论次数一致!优化定时器成功!!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Code_Nice/article/details/52072396

智能推荐

B1003 我要通过! (20分)_wvdon的博客-程序员秘密

1003 我要通过! (20分)“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。得到“答案正确”的条件是:字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A...

vscode如何拉取分支代码_vscode拉取vue指定分支的代码_花霁的博客-程序员秘密

vscode编辑器结合git使用时,只能clone master的代码命令是 git clone XXX, XXX是git代码地址然后我怎么拿到分支代码呢,请看下图:点击图上红圈,出现下图点击远程分支,即可把相应代码拉取下来,其实很简单,但是第一次操作的同学,有可能不知道,希望有帮助!...

PS2018下载PSCC2018安装教程_ps2018安装教程_尹海托的博客-程序员秘密

PSCC2018(64位)下载链接:https://pan.baidu.com/s/1gV9RmsgUdeJ8AXwMXo9aaQ【下载方法】复制下载链接,粘贴纸浏览器网址栏(无提取码)打开,保存到网盘,打开网盘客户端,下载到自己的电脑上;一、安装视频教程https://v.qq.com/x/page/i09273o37sa.html观看1080P高清蓝光更清晰:复制链接粘贴至电脑浏览器或...

在目录中查找包含指定字符串的文件内容查找工具(可搜索各种文件类型,甚至是 exe文件 )帮你在海量文件中快速找到包含指定字符串的文件的工具_快速超找包含指定内容的文件_zyc001的博客-程序员秘密

在电脑中指定目录下有太多文件,各种类型,我想查找包含指定字符的文件,这是我用过的最好最快的工具,能够查找各种类型的文件,甚至是压缩文件和 Exe Dll 文件,I 服了you . 可以定制查找文件的类型,目录 还可以排除指定类型和目录,按日期 大小 查找内容甚至支持复杂的正则表达式。 本人亲自测试非常非常好用 。...

微信内直接下载app和提示前往手机默认浏览器访问指定页面的实现方案,尽在大象跳转..._weixin_33806914的博客-程序员秘密

先到微信跳转API接口平台开通接口权限基于api接口新建一个url=xxx的代码如下访问地址:http://api.go51w.cn/url=http://www.baidu.com(此处改为你的链接)&lt;!DOCTYPEhtml&gt;&lt;htmlxmlns="http://www.mindjump.cn/1999/xhtml"&gt;&lt;hea...

linux服务器非root用户安装tensorflow1.14.0-gpu+cuda10+cudnn7.6_毅强的博客-程序员秘密

实验室新服务器安装tensorflow-gpu,之前安装过一次cpu版本的tensorflow,这次安装gpu版本,出现很多的错误,这里特意将安装tensorflow-gpu的正确方法记录下来,希望对其他人有所帮助。这里是在服务器非root用户上安装,不适用于linux主机上安装tensorflow的用户,还请注意区分。实验环境服务器内核版本:CentOS Linux releas...

随便推点

ubuntu虚拟机配置KVM环境(简单配置)_乌班图虚拟机kvm基于ovs网桥的安装_想养一只咪的博客-程序员秘密

第一步:宿主机环境的搭建保证虚拟化的开启以及桥接模式。第二步:启动或安装ubuntu虚拟机第三步: 配置KVM环境1:确认宿主机是否支持虚拟化egrep -c '(vmx|svm)' /proc/cpuinfo有输出结果大于0,即支持。如果Vmware不启动上图虚拟化支持输出结果则为02: 宿主机安装KVM和相关依赖包sudo apt-get install qemu-kvmsudo apt-get install qemusudo apt-get install virt-mana

Javaweb分页技术实现_张行之的博客-程序员秘密

Javaweb分页技术实现分页技术就是通过SQL语句(如下)来获取数据,具体实现看下面代码//分页查询语句select * from 表名 where limit page , count;和//获取表中的总数据,确定页数select count(*) from 表名;1.配置数据源在项目的WebContent/META-INF目录下创建一个context.xml文件。如图:在context

基于Python词频共现矩阵的计算方法_Artra_Soong的博客-程序员秘密

import pandas as pdimport numpy as npdef gx_matrix(vol_li): # 整合一下,输入是df列,输出直接是矩阵 names = locals() all_col0 = [] # 用来后续求所有字段的集合 for row in vol_li: all_col0 += row for each in row: #对每行的元素进行处理,存在该字段字典的话,再进行后续判断,否则创造该字段字典

C# FFMPEG 直播 主播端程序测试。_omcs底层用的ffmpeg_名字重复好为难的博客-程序员秘密

最近朋友找到我这边,问我会不会做直播程序,Android跟IOS都已经搞定,都是PC端搞不定;研究了下说,这个没问题。收费方向:使用OMCS语音视频框架.免费方向:FFMPEG开源架构.吾等平民只能找开源的试试水.而且还是C语言底层,性能杠杠的.经过测试1.4GHz CPU顶不住压力,带宽约10M能顶住。找到FFMPEG官网,下载操作系统对应的版本.当然也可以下载源代码进...

java log设置level,如何设置Spring Boot测试时的日志级别_weixin_39571403的博客-程序员秘密

1.概览该教程中,我将向你展示:如何在测试时设置spring boot 日志级别。虽然我们可以在测试通过时忽略日志,但是如果需要诊断失败的测试,选择正确的日志级别是非常重要的。2.日志级别的重要性正确设置日志级别可以节省我们许多时间。举例来说,如果测试在CI服务器上失败,但在开发服务器上时却通过了。我们将无法诊断失败的测试,除非有足够的日志输出。为了获取正确数量的详细信息,我们可以微调应用程序的日...

51单片机:LED流水灯(仿真+代码)_木二沐的博客-程序员秘密

这次用单片机做个简单的流水灯。先给大家看一下仿真软件的电路(软件为Proteus)上图就是用仿真软件制作的线路原理图AT89C51RC2:单片机BUTTON:按键CAP:电容CRYSTAL:晶振LED-GERRN:LED灯(绿色)RES:电阻接下来是程序部分(软件为keil)#include"reg51.h" //此文件中定义了单片机的一些特殊功能寄存器#include...

推荐文章

热门文章

相关标签