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