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 cc.ArrayGetIndexOfObject(arr, 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 cc.Assert(callback_fn, "scheduler.scheduleCallbackForTarget() Argument callback_fn must be non-NULL"); 648 cc.Assert(target, "scheduler.scheduleCallbackForTarget() Argument target must be non-NULL"); 649 650 // default arguments 651 interval = interval || 0; 652 repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat; 653 delay = delay || 0; 654 paused = paused || false; 655 656 var element = cc.HASH_FIND_INT(this._hashForTimers, target); 657 658 if (!element) { 659 // Is this the 1st element ? Then set the pause level to all the callback_fns of this target 660 element = new cc.HashTimerEntry(null, target, 0, null, null, paused, null); 661 this._hashForTimers.push(element); 662 } else { 663 cc.Assert(element.paused == paused, "Sheduler.scheduleCallbackForTarget()"); 664 } 665 666 var timer; 667 if (element.timers == null) { 668 element.timers = []; 669 } else { 670 for (var i = 0; i < element.timers.length; i++) { 671 timer = element.timers[i]; 672 if (callback_fn == timer._selector) { 673 cc.log("CCSheduler#scheduleCallback. Callback already scheduled. Updating interval from:" 674 + timer.getInterval().toFixed(4) + " to " + interval.toFixed(4)); 675 timer._interval = interval; 676 return; 677 } 678 } 679 } 680 681 timer = new cc.Timer(); 682 timer.initWithTarget(target, callback_fn, interval, repeat, delay); 683 element.timers.push(timer); 684 }, 685 686 /** 687 * <p> 688 * Schedules the 'update' callback_fn for a given target with a given priority.<br/> 689 * The 'update' callback_fn will be called every frame.<br/> 690 * The lower the priority, the earlier it is called. 691 * </p> 692 * @param {cc.Class} target 693 * @param {Number} priority 694 * @param {Boolean} paused 695 * @example 696 * //register this object to scheduler 697 * cc.Director.getInstance().getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning ); 698 */ 699 scheduleUpdateForTarget:function (target, priority, paused) { 700 var hashElement = cc.HASH_FIND_INT(this._hashForUpdates, target); 701 702 if (hashElement) { 703 if (cc.COCOS2D_DEBUG >= 1) { 704 cc.Assert(hashElement.entry.markedForDeletion, ""); 705 } 706 // TODO: check if priority has changed! 707 hashElement.entry.markedForDeletion = false; 708 return; 709 } 710 711 // most of the updates are going to be 0, that's way there 712 // is an special list for updates with priority 0 713 if (priority == 0) { 714 this._appendIn(this._updates0List, target, paused); 715 } else if (priority < 0) { 716 this._updatesNegList = this._priorityIn(this._updatesNegList, target, priority, paused); 717 } else { 718 // priority > 0 719 this._updatesPosList = this._priorityIn(this._updatesPosList, target, priority, paused); 720 } 721 }, 722 723 /** 724 * <p> 725 * Unschedule a callback function for a given target.<br/> 726 * If you want to unschedule the "update", use unscheudleUpdateForTarget. 727 * </p> 728 * @param {cc.Class} target 729 * @param {function} callback_fn 730 * @example 731 * //unschedule a selector of target 732 * cc.Director.getInstance().getScheduler().unscheduleCallbackForTarget(function, this); 733 */ 734 unscheduleCallbackForTarget:function (target, callback_fn) { 735 // explicity handle nil arguments when removing an object 736 if ((target == null) || (callback_fn == null)) { 737 return; 738 } 739 740 var element = cc.HASH_FIND_INT(this._hashForTimers, target); 741 if (element != null) { 742 for (var i = 0; i < element.timers.length; i++) { 743 var timer = element.timers[i]; 744 if (callback_fn == timer._selector) { 745 if ((timer == element.currentTimer) && (!element.currentTimerSalvaged)) { 746 element.currentTimerSalvaged = true; 747 } 748 cc.ArrayRemoveObjectAtIndex(element.timers, i); 749 //update timerIndex in case we are in tick;, looping over the actions 750 if (element.timerIndex >= i) { 751 element.timerIndex--; 752 } 753 754 if (element.timers.length == 0) { 755 if (this._currentTarget == element) { 756 this._currentTargetSalvaged = true; 757 } else { 758 759 this._removeHashElement(element); 760 } 761 } 762 return; 763 } 764 } 765 } 766 }, 767 768 /** 769 * Unschedules the update callback function for a given target 770 * @param {cc.Class} target 771 * @example 772 * //unschedules the "update" method. 773 * cc.Director.getInstance().getScheduler().unscheduleUpdateForTarget(this); 774 */ 775 unscheduleUpdateForTarget:function (target) { 776 if (target == null) { 777 return; 778 } 779 780 var element = cc.HASH_FIND_INT(this._hashForUpdates, target); 781 if (element != null) { 782 if (this._updateHashLocked) { 783 element.entry.markedForDeletion = true; 784 } else { 785 this._removeUpdateFromHash(element.entry); 786 } 787 } 788 }, 789 790 /** 791 * Unschedules all function callbacks for a given target. This also includes the "update" callback function. 792 * @param {cc.Class} target 793 */ 794 unscheduleAllCallbacksForTarget:function (target) { 795 //explicit NULL handling 796 if (target == null) { 797 return; 798 } 799 800 var element = cc.HASH_FIND_INT(this._hashForTimers, target); 801 if (element) { 802 if ((!element.currentTimerSalvaged) && (cc.ArrayContainsObject(element.timers, element.currentTimer))) { 803 element.currentTimerSalvaged = true; 804 } 805 element.timers.length = 0; 806 807 if (this._currentTarget == element) { 808 this._currentTargetSalvaged = true; 809 } else { 810 this._removeHashElement(element); 811 } 812 } 813 // update selector 814 this.unscheduleUpdateForTarget(target); 815 }, 816 817 /** 818 * <p> 819 * Unschedules all function callbacks from all targets. <br/> 820 * You should NEVER call this method, unless you know what you are doing. 821 * </p> 822 */ 823 unscheduleAllCallbacks:function () { 824 this.unscheduleAllCallbacksWithMinPriority(cc.PRIORITY_SYSTEM); 825 }, 826 827 /** 828 * <p> 829 * Unschedules all function callbacks from all targets with a minimum priority.<br/> 830 * You should only call this with kCCPriorityNonSystemMin or higher. 831 * </p> 832 * @param {Number} minPriority 833 */ 834 unscheduleAllCallbacksWithMinPriority:function (minPriority) { 835 // Custom Selectors 836 var i; 837 for (i = 0; i < this._hashForTimers.length; i++) { 838 // element may be removed in unscheduleAllCallbacksForTarget 839 this.unscheduleAllCallbacksForTarget(this._hashForTimers[i].target); 840 } 841 842 //updates selectors 843 if (minPriority < 0) { 844 for (i = 0; i < this._updatesNegList.length; i++) { 845 this.unscheduleUpdateForTarget(this._updatesNegList[i].target); 846 } 847 } 848 849 if (minPriority <= 0) { 850 for (i = 0; i < this._updates0List.length; i++) { 851 this.unscheduleUpdateForTarget(this._updates0List[i].target); 852 } 853 } 854 855 for (i = 0; i < this._updatesPosList.length; i++) { 856 if (this._updatesPosList[i].priority >= minPriority) { 857 this.unscheduleUpdateForTarget(this._updatesPosList[i].target); 858 } 859 } 860 }, 861 862 /** 863 * <p> 864 * Pause all selectors from all targets.<br/> 865 * You should NEVER call this method, unless you know what you are doing. 866 * </p> 867 */ 868 pauseAllTargets:function () { 869 return this.pauseAllTargetsWithMinPriority(cc.PRIORITY_SYSTEM); 870 }, 871 872 /** 873 * Pause all selectors from all targets with a minimum priority. <br/> 874 * You should only call this with kCCPriorityNonSystemMin or higher. 875 * @param minPriority 876 */ 877 pauseAllTargetsWithMinPriority:function (minPriority) { 878 var idsWithSelectors = []; 879 880 var i, element; 881 // Custom Selectors 882 for (i = 0; i < this._hashForTimers.length; i++) { 883 element = this._hashForTimers[i]; 884 if (element) { 885 element.paused = true; 886 idsWithSelectors.push(element.target); 887 } 888 } 889 890 // Updates selectors 891 if (minPriority < 0) { 892 for (i = 0; i < this._updatesNegList.length; i++) { 893 element = this._updatesNegList[i]; 894 if (element) { 895 element.paused = true; 896 idsWithSelectors.push(element.target); 897 } 898 } 899 } 900 901 if (minPriority <= 0) { 902 for (i = 0; i < this._updates0List.length; i++) { 903 element = this._updates0List[i]; 904 if (element) { 905 element.paused = true; 906 idsWithSelectors.push(element.target); 907 } 908 } 909 } 910 911 for (i = 0; i < this._updatesPosList.length; i++) { 912 element = this._updatesPosList[i]; 913 if (element) { 914 element.paused = true; 915 idsWithSelectors.push(element.target); 916 } 917 } 918 919 return idsWithSelectors; 920 }, 921 922 /** 923 * Resume selectors on a set of targets.<br/> 924 * This can be useful for undoing a call to pauseAllCallbacks. 925 * @param targetsToResume 926 */ 927 resumeTargets:function (targetsToResume) { 928 if (!targetsToResume) 929 return; 930 931 for (var i = 0; i < targetsToResume.length; i++) { 932 this.resumeTarget(targetsToResume[i]); 933 } 934 }, 935 936 /** 937 * <p> 938 * Pauses the target.<br/> 939 * All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.<br/> 940 * If the target is not present, nothing happens. 941 * </p> 942 * @param {cc.Class} target 943 */ 944 pauseTarget:function (target) { 945 cc.Assert(target != null, "Scheduler.pauseTarget():entry must be non nil"); 946 947 //customer selectors 948 var element = cc.HASH_FIND_INT(this._hashForTimers, target); 949 if (element) { 950 element.paused = true; 951 } 952 953 //update selector 954 var elementUpdate = cc.HASH_FIND_INT(this._hashForUpdates, target); 955 if (elementUpdate) { 956 cc.Assert(elementUpdate.entry != null, "Scheduler.pauseTarget():entry must be non nil"); 957 elementUpdate.entry.paused = true; 958 } 959 }, 960 961 /** 962 * Resumes the target.<br/> 963 * The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again.<br/> 964 * If the target is not present, nothing happens. 965 * @param {cc.Class} target 966 */ 967 resumeTarget:function (target) { 968 cc.Assert(target != null, ""); 969 970 // custom selectors 971 var element = cc.HASH_FIND_INT(this._hashForTimers, target); 972 973 if (element) { 974 element.paused = false; 975 } 976 977 //update selector 978 var elementUpdate = cc.HASH_FIND_INT(this._hashForUpdates, target); 979 980 if (elementUpdate) { 981 cc.Assert(elementUpdate.entry != null, "Scheduler.resumeTarget():entry must be non nil"); 982 elementUpdate.entry.paused = false; 983 } 984 }, 985 986 /** 987 * Returns whether or not the target is paused 988 * @param {cc.Class} target 989 * @return {Boolean} 990 */ 991 isTargetPaused:function (target) { 992 cc.Assert(target != null, "Scheduler.isTargetPaused():target must be non nil"); 993 994 // Custom selectors 995 var element = cc.HASH_FIND_INT(this._hashForTimers, target); 996 if (element) { 997 return element.paused; 998 } 999 return false; 1000 } 1001 }); 1002 1003