轉載 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