1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 
 28 /**
 29  * Minimum priority level for user scheduling.
 30  * @constant
 31  * @type Number
 32  */
 33 cc.PRIORITY_NON_SYSTEM = cc.PRIORITY_SYSTEM + 1;
 34 
 35 //data structures
 36 /**
 37  * A list double-linked list used for "updates with priority"
 38  * @Class
 39  * @name cc.ListEntry
 40  * @param {cc.ListEntry} prev
 41  * @param {cc.ListEntry} next
 42  * @param {function} callback
 43  * @param {cc.Class} target not retained (retained by hashUpdateEntry)
 44  * @param {Number} priority
 45  * @param {Boolean} paused
 46  * @param {Boolean} markedForDeletion selector will no longer be called and entry will be removed at end of the next tick
 47  */
 48 cc.ListEntry = function (prev, next, callback, target, priority, paused, markedForDeletion) {
 49     this.prev = prev;
 50     this.next = next;
 51     this.callback = callback;
 52     this.target = target;
 53     this.priority = priority;
 54     this.paused = paused;
 55     this.markedForDeletion = markedForDeletion;
 56 };
 57 
 58 /**
 59  * A update entry list
 60  * @Class
 61  * @name cc.HashUpdateEntry
 62  * @param {Array} list Which list does it belong to ?
 63  * @param {cc.ListEntry} entry entry in the list
 64  * @param {cc.Class} target hash key (retained)
 65  * @param {function} callback
 66  * @param {Array} hh
 67  */
 68 cc.HashUpdateEntry = function (list, entry, target, callback, hh) {
 69     this.list = list;
 70     this.entry = entry;
 71     this.target = target;
 72     this.callback = callback;
 73     this.hh = hh;
 74 };
 75 
 76 //
 77 /**
 78  * Hash Element used for "selectors with interval"
 79  * @Class
 80  * @param {Array} timers
 81  * @param {cc.Class} target  hash key (retained)
 82  * @param {Number} timerIndex
 83  * @param {cc.Timer} currentTimer
 84  * @param {Boolean} currentTimerSalvaged
 85  * @param {Boolean} paused
 86  * @param {Array} hh
 87  */
 88 cc.HashTimerEntry = cc.hashSelectorEntry = function (timers, target, timerIndex, currentTimer, currentTimerSalvaged, paused, hh) {
 89     var _t = this;
 90     _t.timers = timers;
 91     _t.target = target;
 92     _t.timerIndex = timerIndex;
 93     _t.currentTimer = currentTimer;
 94     _t.currentTimerSalvaged = currentTimerSalvaged;
 95     _t.paused = paused;
 96     _t.hh = hh;
 97 };
 98 
 99 /**
100  * Light weight timer
101  * @class
102  * @extends cc.Class
103  */
104 cc.Timer = cc.Class.extend(/** @lends cc.Timer# */{
105     _scheduler: null,
106     _elapsed:0.0,
107     _runForever:false,
108     _useDelay:false,
109     _timesExecuted:0,
110     _repeat:0, //0 = once, 1 is 2 x executed
111     _delay:0,
112     _interval:0.0,
113 
114     /**
115      * @return {Number} returns interval of timer
116      */
117     getInterval : function(){return this._interval;},
118     /**
119      * @param {Number} interval set interval in seconds
120      */
121     setInterval : function(interval){this._interval = interval;},
122 
123     setupTimerWithInterval: function(seconds, repeat, delay){
124         this._elapsed = -1;
125         this._interval = seconds;
126         this._delay = delay;
127         this._useDelay = (this._delay > 0);
128         this._repeat = repeat;
129         this._runForever = (this._repeat === cc.REPEAT_FOREVER);
130     },
131 
132     trigger: function(){
133         return 0;
134     },
135 
136     cancel: function(){
137         return 0;
138     },
139 
140     /**
141      * cc.Timer's Constructor
142      * Constructor of cc.Timer
143      */
144     ctor:function () {
145         this._scheduler = null;
146         this._elapsed = -1;
147         this._runForever = false;
148         this._useDelay = false;
149         this._timesExecuted = 0;
150         this._repeat = 0;
151         this._delay = 0;
152         this._interval = 0;
153     },
154 
155     /**
156      * triggers the timer
157      * @param {Number} dt delta time
158      */
159     update:function (dt) {
160         if (this._elapsed === -1) {
161             this._elapsed = 0;
162             this._timesExecuted = 0;
163         } else {
164             this._elapsed += dt;
165             if (this._runForever && !this._useDelay) {//standard timer usage
166                 if (this._elapsed >= this._interval) {
167                     this.trigger();
168                     this._elapsed = 0;
169                 }
170             } else {//advanced usage
171                 if (this._useDelay) {
172                     if (this._elapsed >= this._delay) {
173                         this.trigger();
174 
175                         this._elapsed -= this._delay;
176                         this._timesExecuted += 1;
177                         this._useDelay = false;
178                     }
179                 } else {
180                     if (this._elapsed >= this._interval) {
181                         this.trigger();
182 
183                         this._elapsed = 0;
184                         this._timesExecuted += 1;
185                     }
186                 }
187 
188                 if (!this._runForever && this._timesExecuted > this._repeat)
189                     this.cancel();
190             }
191         }
192     }
193 });
194 
195 cc.TimerTargetSelector = cc.Timer.extend({
196     _target: null,
197     _selector: null,
198 
199     ctor: function(){
200         this._target = null;
201         this._selector = null;
202     },
203 
204     initWithSelector: function(scheduler, selector, target, seconds, repeat, delay){
205         this._scheduler = scheduler;
206         this._target = target;
207         this._selector = selector;
208         this.setupTimerWithInterval(seconds, repeat, delay);
209         return true;
210     },
211 
212     getSelector: function(){
213         return this._selector;
214     },
215 
216     trigger: function(){
217         //override
218         if (this._target && this._selector){
219             this._target.call(this._selector, this._elapsed);
220         }
221     },
222 
223     cancel: function(){
224         //override
225         this._scheduler.unschedule(this._selector, this._target);
226     }
227 
228 });
229 
230 cc.TimerTargetCallback = cc.Timer.extend({
231 
232     _target: null,
233     _callback: null,
234     _key: null,
235 
236     ctor: function(){
237         this._target = null;
238         this._callback = null;
239     },
240 
241     initWithCallback: function(scheduler, callback, target, key, seconds, repeat, delay){
242         this._scheduler = scheduler;
243         this._target = target;
244         this._callback = callback;
245         this._key = key;
246         this.setupTimerWithInterval(seconds, repeat, delay);
247         return true;
248     },
249 
250     getCallback: function(){
251         return this._callback;
252     },
253 
254     getKey: function(){
255         return this._key;
256     },
257 
258     trigger: function(){
259         //override
260         if(this._callback)
261             this._callback.call(this._target, this._elapsed);
262     },
263 
264     cancel: function(){
265         //override
266         this._scheduler.unschedule(this._callback, this._target);
267     }
268 
269 });
270 
271 /**
272  * <p>
273  *    Scheduler is responsible of triggering the scheduled callbacks.<br/>
274  *    You should not use NSTimer. Instead use this class.<br/>
275  *    <br/>
276  *    There are 2 different types of callbacks (selectors):<br/>
277  *       - update callback: the 'update' callback will be called every frame. You can customize the priority.<br/>
278  *       - custom callback: A custom callback will be called every frame, or with a custom interval of time<br/>
279  *       <br/>
280  *    The 'custom selectors' should be avoided when possible. It is faster, and consumes less memory to use the 'update callback'. *
281  * </p>
282  * @class
283  * @extends cc.Class
284  *
285  * @example
286  * //register a schedule to scheduler
287  * cc.director.getScheduler().schedule(callback, this, interval, !this._isRunning);
288  */
289 cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{
290     _timeScale:1.0,
291 
292     //_updates : null, //_updates[0] list of priority < 0, _updates[1] list of priority == 0, _updates[2] list of priority > 0,
293     _updatesNegList: null,
294     _updates0List: null,
295     _updatesPosList: null,
296 
297     _hashForTimers:null, //Used for "selectors with interval"
298     _arrayForTimers:null, //Speed up indexing
299     _hashForUpdates:null, // hash used to fetch quickly the list entries for pause,delete,etc
300     //_arrayForUpdates:null, //Speed up indexing
301 
302     _currentTarget:null,
303     _currentTargetSalvaged:false,
304     _updateHashLocked:false, //If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
305 
306 
307     ctor:function () {
308         this._timeScale = 1.0;
309         this._updatesNegList = [];
310         this._updates0List = [];
311         this._updatesPosList = [];
312 
313         this._hashForUpdates = {};
314         this._hashForTimers = {};
315         this._currentTarget = null;
316         this._currentTargetSalvaged = false;
317         this._updateHashLocked = false;
318 
319         this._arrayForTimers = [];
320         //this._arrayForUpdates = [];
321 
322     },
323 
324     //-----------------------private method----------------------
325 
326     _schedulePerFrame: function(callback, target, priority, paused){
327         var hashElement = this._hashForUpdates[target.__instanceId];
328         if (hashElement && hashElement.entry){
329             // check if priority has changed
330             if (hashElement.entry.priority !== priority){
331                 if (this._updateHashLocked){
332                     cc.log("warning: you CANNOT change update priority in scheduled function");
333                     hashElement.entry.markedForDeletion = false;
334                     hashElement.entry.paused = paused;
335                     return;
336                 }else{
337                     // will be added again outside if (hashElement).
338                     this.unscheduleUpdate(target);
339                 }
340             }else{
341                 hashElement.entry.markedForDeletion = false;
342                 hashElement.entry.paused = paused;
343                 return;
344             }
345         }
346 
347         // most of the updates are going to be 0, that's way there
348         // is an special list for updates with priority 0
349         if (priority === 0){
350             this._appendIn(this._updates0List, callback, target, paused);
351         }else if (priority < 0){
352             this._priorityIn(this._updatesNegList, callback, target, priority, paused);
353         }else{
354             // priority > 0
355             this._priorityIn(this._updatesPosList, callback, target, priority, paused);
356         }
357     },
358 
359     _removeHashElement:function (element) {
360         delete this._hashForTimers[element.target.__instanceId];
361         cc.arrayRemoveObject(this._arrayForTimers, element);
362         element.Timer = null;
363         element.target = null;
364         element = null;
365     },
366 
367     _removeUpdateFromHash:function (entry) {
368         var self = this, element = self._hashForUpdates[entry.target.__instanceId];
369         if (element) {
370             //list entry
371             cc.arrayRemoveObject(element.list, element.entry);
372 
373             delete self._hashForUpdates[element.target.__instanceId];
374             //cc.arrayRemoveObject(self._hashForUpdates, element);
375             element.entry = null;
376 
377             //hash entry
378             element.target = null;
379         }
380     },
381 
382     _priorityIn:function (ppList, callback,  target, priority, paused) {
383         var self = this,
384             listElement = new cc.ListEntry(null, null, callback, target, priority, paused, false);
385 
386         // empey list ?
387         if (!ppList) {
388             ppList = [];
389             ppList.push(listElement);
390         } else {
391             var index2Insert = ppList.length - 1;
392             for(var i = 0; i <= index2Insert; i++){
393                 if (priority < ppList[i].priority) {
394                     index2Insert = i;
395                     break;
396                 }
397             }
398             ppList.splice(i, 0, listElement);
399         }
400 
401         //update hash entry for quick access
402         self._hashForUpdates[target.__instanceId] = new cc.HashUpdateEntry(ppList, listElement, target, null);
403 
404         return ppList;
405     },
406 
407     _appendIn:function (ppList, callback, target, paused) {
408         var self = this, listElement = new cc.ListEntry(null, null, callback, target, 0, paused, false);
409         ppList.push(listElement);
410 
411         //update hash entry for quicker access
412         self._hashForUpdates[target.__instanceId] = new cc.HashUpdateEntry(ppList, listElement, target, null, null);
413     },
414 
415     //-----------------------public method-------------------------
416     /**
417      * <p>
418      *    Modifies the time of all scheduled callbacks.<br/>
419      *    You can use this property to create a 'slow motion' or 'fast forward' effect.<br/>
420      *    Default is 1.0. To create a 'slow motion' effect, use values below 1.0.<br/>
421      *    To create a 'fast forward' effect, use values higher than 1.0.<br/>
422      *    @warning It will affect EVERY scheduled selector / action.
423      * </p>
424      * @param {Number} timeScale
425      */
426     setTimeScale:function (timeScale) {
427         this._timeScale = timeScale;
428     },
429 
430     /**
431      * Returns time scale of scheduler
432      * @return {Number}
433      */
434     getTimeScale:function () {
435         return this._timeScale;
436     },
437 
438     /**
439      * 'update' the scheduler. (You should NEVER call this method, unless you know what you are doing.)
440      * @param {Number} dt delta time
441      */
442     update:function (dt) {
443         this._updateHashLocked = true;
444         if(this._timeScale !== 1)
445             dt *= this._timeScale;
446 
447         var i, list, len, entry;
448 
449         for(i=0,list=this._updatesNegList, len = list.length; i<len; i++){
450             entry = list[i];
451             if(!entry.paused && !entry.markedForDeletion)
452                 entry.callback(dt);
453         }
454 
455         for(i=0, list=this._updates0List, len=list.length; i<len; i++){
456             entry = list[i];
457             if (!entry.paused && !entry.markedForDeletion)
458                 entry.callback(dt);
459         }
460 
461         for(i=0, list=this._updatesPosList, len=list.length; i<len; i++){
462             entry = list[i];
463             if (!entry.paused && !entry.markedForDeletion)
464                 entry.callback(dt);
465         }
466 
467         // Iterate over all the custom selectors
468         var elt, arr = this._arrayForTimers;
469         for(i=0; i<arr.length; i++){
470             elt = arr[i];
471             this._currentTarget = elt;
472             this._currentTargetSalvaged = false;
473 
474             if (!elt.paused){
475                 // The 'timers' array may change while inside this loop
476                 for (elt.timerIndex = 0; elt.timerIndex < elt.timers.length; ++(elt.timerIndex)){
477                     elt.currentTimer = elt.timers[elt.timerIndex];
478                     elt.currentTimerSalvaged = false;
479 
480                     elt.currentTimer.update(dt);
481                     elt.currentTimer = null;
482                 }
483             }
484 
485             // elt, at this moment, is still valid
486             // so it is safe to ask this here (issue #490)
487             //elt = elt.hh.next;
488 
489             // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
490             if (this._currentTargetSalvaged && this._currentTarget.timers.length === 0)
491                 this._removeHashElement(this._currentTarget);
492         }
493 
494         // delete all updates that are marked for deletion
495         // updates with priority < 0
496         for(i=0,list=this._updatesNegList; i<list.length; ){
497             entry = list[i];
498             if(entry.markedForDeletion)
499                 this._removeUpdateFromHash(entry);
500             else
501                 i++;
502         }
503 
504         for(i=0, list=this._updates0List; i<list.length; ){
505             entry = list[i];
506             if (entry.markedForDeletion)
507                 this._removeUpdateFromHash(entry);
508             else
509                 i++;
510         }
511 
512         for(i=0, list=this._updatesPosList; i<list.length; ){
513             entry = list[i];
514             if (entry.markedForDeletion)
515                 this._removeUpdateFromHash(entry);
516             else
517                 i++;
518         }
519 
520         this._updateHashLocked = false;
521         this._currentTarget = null;
522     },
523 
524     /**
525      * <p>
526      *   The scheduled method will be called every 'interval' seconds.</br>
527      *   If paused is YES, then it won't be called until it is resumed.<br/>
528      *   If 'interval' is 0, it will be called every frame, but if so, it recommended to use 'scheduleUpdateForTarget:' instead.<br/>
529      *   If the callback function is already scheduled, then only the interval parameter will be updated without re-scheduling it again.<br/>
530      *   repeat let the action be repeated repeat + 1 times, use cc.REPEAT_FOREVER to let the action run continuously<br/>
531      *   delay is the amount of time the action will wait before it'll start<br/>
532      * </p>
533      * @deprecated since v3.4 please use .schedule
534      * @param {cc.Class} target
535      * @param {function} callback_fn
536      * @param {Number} interval
537      * @param {Number} repeat
538      * @param {Number} delay
539      * @param {Boolean} paused
540      * @example
541      * //register a schedule to scheduler
542      * cc.director.getScheduler().scheduleCallbackForTarget(this, function, interval, repeat, delay, !this._isRunning );
543      */
544     scheduleCallbackForTarget: function(target, callback_fn, interval, repeat, delay, paused){
545         //cc.log("scheduleCallbackForTarget is deprecated. Please use schedule.");
546         this.schedule(callback_fn, target, interval, repeat, delay, paused, target.__instanceId + "");
547     },
548 
549     schedule: function(callback, target, interval, repeat, delay, paused, key){
550         var isSelector = false;
551         if(typeof callback !== "function"){
552             var selector = callback;
553             isSelector = true;
554         }
555 
556         if(isSelector === false){
557             //callback, target, interval, repeat, delay, paused, key
558             //callback, target, interval, paused, key
559             if(arguments.length === 4 || arguments.length === 5){
560                 key = delay;
561                 paused = repeat;
562                 delay = 0;
563                 repeat = cc.REPEAT_FOREVER;
564             }
565         }else{
566             //selector, target, interval, repeat, delay, paused
567             //selector, target, interval, paused
568             if(arguments.length === 4){
569                 paused = repeat;
570                 repeat = cc.REPEAT_FOREVER;
571                 delay = 0;
572             }
573         }
574         if (key === undefined) {
575             key = target.__instanceId + "";
576         }
577 
578         cc.assert(target, cc._LogInfos.Scheduler_scheduleCallbackForTarget_3);
579 
580         var element = this._hashForTimers[target.__instanceId];
581 
582         if(!element){
583             // Is this the 1st element ? Then set the pause level to all the callback_fns of this target
584             element = new cc.HashTimerEntry(null, target, 0, null, null, paused, null);
585             this._arrayForTimers.push(element);
586             this._hashForTimers[target.__instanceId] = element;
587         }else{
588             cc.assert(element.paused === paused, "");
589         }
590 
591         var timer, i;
592         if (element.timers == null) {
593             element.timers = [];
594         } else if(isSelector === false) {
595             for (i = 0; i < element.timers.length; i++) {
596                 timer = element.timers[i];
597                 if (callback === timer._callback) {
598                     cc.log(cc._LogInfos.Scheduler_scheduleCallbackForTarget, timer.getInterval().toFixed(4), interval.toFixed(4));
599                     timer._interval = interval;
600                     return;
601                 }
602             }
603         }else{
604             for (i = 0; i < element.timers.length; ++i){
605                 timer =element.timers[i];
606                 if (timer && selector === timer.getSelector()){
607                     cc.log("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer.getInterval(), interval);
608                     timer.setInterval(interval);
609                     return;
610                 }
611             }
612             //ccArrayEnsureExtraCapacity(element->timers, 1);
613         }
614 
615         if(isSelector === false){
616             timer = new cc.TimerTargetCallback();
617             timer.initWithCallback(this, callback, target, key, interval, repeat, delay);
618             element.timers.push(timer);
619         }else{
620             timer = new cc.TimerTargetSelector();
621             timer.initWithSelector(this, selector, target, interval, repeat, delay);
622             element.timers.push(timer);
623         }
624     },
625 
626     scheduleUpdate: function(target, priority, paused){
627         this._schedulePerFrame(function(dt){
628             target.update(dt);
629         }, target, priority, paused);
630     },
631 
632     _getUnscheduleMark: function(key, timer){
633         //key, callback, selector
634         switch (typeof key){
635             case "number":
636             case "string":
637                 return key === timer.getKey();
638             case "function":
639                 return key === timer._callback;
640             default:
641                 return key === timer.getSelector();
642         }
643     },
644     unschedule: function(key, target){
645         //key, target
646         //selector, target
647         //callback, target - This is in order to increase compatibility
648 
649         // explicity handle nil arguments when removing an object
650         if (!target || !key)
651             return;
652 
653         var self = this, element = self._hashForTimers[target.__instanceId];
654         if (element) {
655             var timers = element.timers;
656             for(var i = 0, li = timers.length; i < li; i++){
657                 var timer = timers[i];
658                 if (this._getUnscheduleMark(key, timer)) {
659                     if ((timer === element.currentTimer) && (!element.currentTimerSalvaged)) {
660                         element.currentTimerSalvaged = true;
661                     }
662                     timers.splice(i, 1);
663                     //update timerIndex in case we are in tick;, looping over the actions
664                     if (element.timerIndex >= i) {
665                         element.timerIndex--;
666                     }
667 
668                     if (timers.length === 0) {
669                         if (self._currentTarget === element) {
670                             self._currentTargetSalvaged = true;
671                         } else {
672                             self._removeHashElement(element);
673                         }
674                     }
675                     return;
676                 }
677             }
678         }
679     },
680 
681     unscheduleUpdate: function(target){
682         if (target == null)
683             return;
684 
685         var element = this._hashForUpdates[target.__instanceId];
686 
687         if (element){
688             if (this._updateHashLocked){
689                 element.entry.markedForDeletion = true;
690             }else{
691                 this._removeUpdateFromHash(element.entry);
692             }
693         }
694     },
695 
696     unscheduleAllForTarget: function(target){
697         // explicit nullptr handling
698         if (target == null){
699             return;
700         }
701 
702         // Custom Selectors
703         var element = this._hashForTimers[target.__instanceId];
704 
705         if (element){
706             if (element.timers.indexOf(element.currentTimer) > -1
707                 && (! element.currentTimerSalvaged)){
708                 element.currentTimerSalvaged = true;
709             }
710             //        ccArrayRemoveAllObjects(element.timers);
711             element.timers.length = 0;
712 
713             if (this._currentTarget === element){
714                 this._currentTargetSalvaged = true;
715             }else{
716                 this._removeHashElement(element);
717             }
718         }
719 
720         // update selector
721         this.unscheduleUpdate(target);
722     },
723 
724     unscheduleAll: function(){
725         this.unscheduleAllWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
726     },
727 
728     unscheduleAllWithMinPriority: function(minPriority){
729         // Custom Selectors
730         var i, element, arr = this._arrayForTimers;
731         for(i=arr.length-1; i>=0; i--){
732             element = arr[i];
733             this.unscheduleAllForTarget(element.target);
734         }
735 
736         // Updates selectors
737         var entry;
738         var temp_length = 0;
739         if(minPriority < 0){
740             for(i=0; i<this._updatesNegList.length; ){
741                 temp_length = this._updatesNegList.length;
742                 entry = this._updatesNegList[i];
743                 if(entry && entry.priority >= minPriority)
744                     this.unscheduleUpdate(entry.target);
745                 if (temp_length == this._updatesNegList.length)
746                     i++;
747             }
748         }
749 
750         if(minPriority <= 0){
751             for(i=0; i<this._updates0List.length; ){
752                 temp_length = this._updates0List.length;
753                 entry = this._updates0List[i];
754                 if (entry)
755                     this.unscheduleUpdate(entry.target);
756                 if (temp_length == this._updates0List.length)
757                     i++;
758             }
759         }
760 
761         for(i=0; i<this._updatesPosList.length; ){
762             temp_length = this._updatesPosList.length;
763             entry = this._updatesPosList[i];
764             if(entry && entry.priority >= minPriority)
765                 this.unscheduleUpdate(entry.target);
766             if (temp_length == this._updatesPosList.length)
767                 i++;
768         }
769     },
770 
771     isScheduled: function(key, target){
772         //key, target
773         //selector, target
774         cc.assert(key, "Argument key must not be empty");
775         cc.assert(target, "Argument target must be non-nullptr");
776 
777         var element = this._hashForUpdates[target.__instanceId];
778 
779         if (!element){
780             return false;
781         }
782 
783         if (element.timers == null){
784             return false;
785         }else{
786             var timers = element.timers;
787             for (var i = 0; i < timers.length; ++i){
788                 var timer =  timers[i];
789 
790                 if (key === timer.getKey()){
791                     return true;
792                 }
793             }
794             return false;
795         }
796     },
797 
798     /**
799      * <p>
800      *  Pause all selectors from all targets.<br/>
801      *  You should NEVER call this method, unless you know what you are doing.
802      * </p>
803      */
804     pauseAllTargets:function () {
805         return this.pauseAllTargetsWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
806     },
807 
808     /**
809      * Pause all selectors from all targets with a minimum priority. <br/>
810      * You should only call this with kCCPriorityNonSystemMin or higher.
811      * @param {Number} minPriority
812      */
813     pauseAllTargetsWithMinPriority:function (minPriority) {
814         var idsWithSelectors = [];
815 
816         var self = this, element, locArrayForTimers = self._arrayForTimers;
817         var i, li;
818         // Custom Selectors
819         for(i = 0, li = locArrayForTimers.length; i < li; i++){
820             element = locArrayForTimers[i];
821             if (element) {
822                 element.paused = true;
823                 idsWithSelectors.push(element.target);
824             }
825         }
826 
827         var entry;
828         if(minPriority < 0){
829             for(i=0; i<this._updatesNegList.length; i++){
830                 entry = this._updatesNegList[i];
831                 if (entry) {
832                     if(entry.priority >= minPriority){
833 						entry.paused = true;
834                         idsWithSelectors.push(entry.target);
835                     }
836                 }
837             }
838         }
839 
840         if(minPriority <= 0){
841             for(i=0; i<this._updates0List.length; i++){
842                 entry = this._updates0List[i];
843                 if (entry) {
844 					entry.paused = true;
845                     idsWithSelectors.push(entry.target);
846                 }
847             }
848         }
849 
850         for(i=0; i<this._updatesPosList.length; i++){
851             entry = this._updatesPosList[i];
852             if (entry) {
853                 if(entry.priority >= minPriority){
854 					entry.paused = true;
855                     idsWithSelectors.push(entry.target);
856                 }
857             }
858         }
859 
860         return idsWithSelectors;
861     },
862 
863     /**
864      * Resume selectors on a set of targets.<br/>
865      * This can be useful for undoing a call to pauseAllCallbacks.
866      * @param {Array} targetsToResume
867      */
868     resumeTargets:function (targetsToResume) {
869         if (!targetsToResume)
870             return;
871 
872         for (var i = 0; i < targetsToResume.length; i++) {
873             this.resumeTarget(targetsToResume[i]);
874         }
875     },
876 
877     /**
878      * <p>
879      *    Pauses the target.<br/>
880      *    All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.<br/>
881      *    If the target is not present, nothing happens.
882      * </p>
883      * @param {cc.Class} target
884      */
885     pauseTarget:function (target) {
886 
887         cc.assert(target, cc._LogInfos.Scheduler_pauseTarget);
888 
889         //customer selectors
890         var self = this, element = self._hashForTimers[target.__instanceId];
891         if (element) {
892             element.paused = true;
893         }
894 
895         //update callback
896         var elementUpdate = self._hashForUpdates[target.__instanceId];
897         if (elementUpdate) {
898             elementUpdate.entry.paused = true;
899         }
900     },
901 
902     /**
903      * Resumes the target.<br/>
904      * The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again.<br/>
905      * If the target is not present, nothing happens.
906      * @param {cc.Class} target
907      */
908     resumeTarget:function (target) {
909 
910         cc.assert(target, cc._LogInfos.Scheduler_resumeTarget);
911 
912         // custom selectors
913         var self = this, element = self._hashForTimers[target.__instanceId];
914 
915         if (element) {
916             element.paused = false;
917         }
918 
919         //update callback
920         var elementUpdate = self._hashForUpdates[target.__instanceId];
921 
922         if (elementUpdate) {
923             elementUpdate.entry.paused = false;
924         }
925     },
926 
927     /**
928      * Returns whether or not the target is paused
929      * @param {cc.Class} target
930      * @return {Boolean}
931      */
932     isTargetPaused:function (target) {
933 
934         cc.assert(target, cc._LogInfos.Scheduler_isTargetPaused);
935 
936         // Custom selectors
937         var element = this._hashForTimers[target.__instanceId];
938         if (element) {
939             return element.paused;
940         }
941         var elementUpdate = this._hashForUpdates[target.__instanceId];
942         if (elementUpdate) {
943             return elementUpdate.entry.paused;
944         }
945         return false;
946     },
947 
948     /**
949      * <p>
950      *    Schedules the 'update' callback_fn for a given target with a given priority.<br/>
951      *    The 'update' callback_fn will be called every frame.<br/>
952      *    The lower the priority, the earlier it is called.
953      * </p>
954      * @deprecated since v3.4 please use .scheduleUpdate
955      * @param {cc.Class} target
956      * @param {Number} priority
957      * @param {Boolean} paused
958      * @example
959      * //register this object to scheduler
960      * cc.director.getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning );
961      */
962     scheduleUpdateForTarget: function(target, priority, paused){
963         //cc.log("scheduleUpdateForTarget is deprecated. Please use scheduleUpdate.");
964         this.scheduleUpdate(target, priority, paused);
965     },
966 
967     /**
968      * <p>
969      *   Unschedule a callback function for a given target.<br/>
970      *   If you want to unschedule the "update", use unscheudleUpdateForTarget.
971      * </p>
972      * @deprecated since v3.4 please use .unschedule
973      * @param {cc.Class} target
974      * @param {function} callback callback[Function] or key[String]
975      * @example
976      * //unschedule a callback of target
977      * cc.director.getScheduler().unscheduleCallbackForTarget(function, this);
978      */
979     unscheduleCallbackForTarget:function (target, callback) {
980         //cc.log("unscheduleCallbackForTarget is deprecated. Please use unschedule.");
981         this.unschedule(callback, target);
982     },
983 
984     /**
985      * Unschedules the update callback function for a given target
986      * @param {cc.Class} target
987      * @deprecated since v3.4 please use .unschedule
988      * @example
989      * //unschedules the "update" method.
990      * cc.director.getScheduler().unscheduleUpdateForTarget(this);
991      */
992     unscheduleUpdateForTarget:function (target) {
993         //cc.log("unscheduleUpdateForTarget is deprecated. Please use unschedule.");
994         this.unscheduleUpdate(target);
995     },
996 
997     /**
998      * Unschedules all function callbacks for a given target. This also includes the "update" callback function.
999      * @deprecated since v3.4 please use .unscheduleAll
1000      * @param {cc.Class} target
1001      */
1002     unscheduleAllCallbacksForTarget: function(target){
1003         //cc.log("unscheduleAllCallbacksForTarget is deprecated. Please use unscheduleAll.");
1004         this.unschedule(target.__instanceId + "", target);
1005     },
1006 
1007     /**
1008      *  <p>
1009      *      Unschedules all function callbacks from all targets. <br/>
1010      *      You should NEVER call this method, unless you know what you are doing.
1011      *  </p>
1012      * @deprecated since v3.4 please use .unscheduleAllWithMinPriority
1013      */
1014     unscheduleAllCallbacks: function(){
1015         //cc.log("unscheduleAllCallbacks is deprecated. Please use unscheduleAll.");
1016         this.unscheduleAllWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
1017     },
1018 
1019     /**
1020      * <p>
1021      *    Unschedules all function callbacks from all targets with a minimum priority.<br/>
1022      *    You should only call this with kCCPriorityNonSystemMin or higher.
1023      * </p>
1024      * @deprecated since v3.4 please use .unscheduleAllWithMinPriority
1025      * @param {Number} minPriority
1026      */
1027     unscheduleAllCallbacksWithMinPriority:function (minPriority) {
1028         //cc.log("unscheduleAllCallbacksWithMinPriority is deprecated. Please use unscheduleAllWithMinPriority.");
1029         this.unscheduleAllWithMinPriority(minPriority);
1030     }
1031 });
1032 /**
1033  * Priority level reserved for system services.
1034  * @constant
1035  * @type Number
1036  */
1037 cc.Scheduler.PRIORITY_SYSTEM = (-2147483647 - 1);
1038