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