cocos2d -js 解決定時器schedule誤差

轉載 http://www.cnblogs.com/kenkofox/p/4138048.html

對於動畫控制,可能一點誤差,大家不會察覺,但如果多次循環累積或網絡同步等,大家就會很清楚意識到schedule的誤差問題。

 

首先做一個例子證明一下:

複製代碼
var InaccuracyTestLayer = cc.Layer.extend({

    ctor: function () {
        this._super();
        var startTime = new Date().getTime();
        var count = 0;
        this.schedule(function(){
            var timePass = new Date().getTime() - startTime;
            count++;
            var delta = timePass - (count*100);
            trace("time pass", timePass, "total delta", delta, "count", count);
        }, 0.1);

        this.scheduleUpdate();
    },

    update: function () {
        for (var i = 0; i < 100000; i++) {
            b = 1/0.22222;
        }
    }
});
複製代碼

 

幀頻越低,變慢得越快。

time pass, 1481, total delta, 381, count, 11 CCDebugger.js:334
time pass, 1608, total delta, 408, count, 12 CCDebugger.js:334
time pass, 1735, total delta, 435, count, 13 CCDebugger.js:334
time pass, 1861, total delta, 461, count, 14 CCDebugger.js:334

 

那麼嘗試一下解決問題?

定時器原理:cocos2d-js底層在每一幀計算中,遍歷所有定時器,看是否達到觸發時間。如果達到則觸發該定時器,並把時間重置爲當前時間。好了,問題就在於此,“重置爲當前時間”。

 

看看一個新的定時器:

複製代碼
    schedule2: function (callback, interval) {
        var then = Date.now();
        interval = interval*1000;
        this.schedule(function(){
            var now = Date.now();
            var delta = now - then;
            if(delta > interval){
                then = now - (delta % interval);
                callback.call(this);
            }
        }.bind(this), 0);
    }
複製代碼

這裏核心是then=now-(delta%interval),每一次觸發的時候,把誤差算到下次觸發的控制中。

例如60fps,那麼schedule2每16ms觸發一次,用戶設定了100ms的interval,那麼將有16*7=112>100,7幀才觸發1次用戶的定時器。這裏累積了12ms誤差,把12ms算到then中。

那麼下次將有12+16*6=108>100,只需要96ms就觸發第2次用戶的定時器,這次提前了4ms,彌補了第1次的誤差。

 

這個定時器經得起考驗,即使在低幀頻情況下,仍然保持穩定。

複製代碼
var BetterScheduleLayer = cc.Layer.extend({

    ctor: function () {
        this._super();

        var startTime = Date.now();
        var count = 0;
        this.schedule2(function(){
            var timePass = Date.now() - startTime;
            count++;
            var delta = timePass - (count*100);
            trace("time pass", timePass, "total delta", delta, "count", count);
        }, 0.1);
        this.scheduleUpdate();
    },

    schedule2: function (callback, interval) {
        var then = Date.now();
        interval = interval*1000;
        this.schedule(function(){
            var now = Date.now();
            var delta = now - then;
            if(delta > interval){
                then = now - (delta % interval);
                callback.call(this);
            }
        }.bind(this), 0);
    },

    update: function () {
        for (var i = 0; i < 10000000; i++) {
            b = 1/0.22222;
        }
    }
});
複製代碼

輸出:

time pass, 3447, total delta, 47, count, 34 CCDebugger.js:334
time pass, 3510, total delta, 10, count, 35 CCDebugger.js:334
time pass, 3637, total delta, 37, count, 36 CCDebugger.js:334
time pass, 3701, total delta, 1, count, 37 CCDebugger.js:334
time pass, 3828, total delta, 28, count, 38 CCDebugger.js:334
time pass, 3955, total delta, 55, count, 39 CCDebugger.js:334

 

[email protected] https://github.com/kenkozheng
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章