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 _arrayForUpdates:null, 418 419 _hashForTimers:null, //Used for "selectors with interval" 420 _arrayForTimes:null, 421 422 _currentTarget:null, 423 _currentTargetSalvaged:false, 424 _updateHashLocked:false, //If true unschedule will not remove anything from a hash. Elements will only be marked for deletion. 425 426 /** 427 * Constructor 428 */ 429 ctor:function () { 430 this._timeScale = 1.0; 431 432 this._updatesNegList = []; 433 this._updates0List = []; 434 this._updatesPosList = []; 435 436 this._hashForUpdates = {}; 437 this._arrayForUpdates = []; 438 439 this._hashForTimers = {}; 440 this._arrayForTimers = []; 441 442 this._currentTarget = null; 443 this._currentTargetSalvaged = false; 444 this._updateHashLocked = false; 445 }, 446 447 //-----------------------private method---------------------- 448 _removeHashElement:function (element) { 449 delete this._hashForTimers[element.target.__instanceId]; 450 cc.ArrayRemoveObject(this._arrayForTimers, element); 451 element.Timer = null; 452 element.target = null; 453 element = null; 454 }, 455 456 /** 457 * find Object from Array 458 * @private 459 * @param {Array} array Array 460 * @param {cc.Class} target object 461 * @return {cc.ListEntry} object if found, or return null 462 */ 463 _findElementFromArray:function (array, target) { 464 for (var i = 0; i < array.length; i++) { 465 if (array[i].target == target) { 466 return array[i]; 467 } 468 } 469 return null; 470 }, 471 472 _removeUpdateFromHash:function (entry) { 473 // var element = this._findElementFromArray(this._hashForUpdates, entry.target); 474 var element = this._hashForUpdates[entry.target.__instanceId]; 475 if (element) { 476 //list entry 477 cc.ArrayRemoveObject(element.list, element.entry); 478 479 delete this._hashForUpdates[element.target.__instanceId]; 480 cc.ArrayRemoveObject(this._arrayForUpdates, element); 481 element.entry = null; 482 483 //hash entry 484 element.target = null; 485 // cc.ArrayRemoveObject(this._hashForUpdates, element); 486 } 487 }, 488 489 _priorityIn:function (ppList, target, priority, paused) { 490 var listElement = new cc.ListEntry(null, null, target, priority, paused, false); 491 492 // empey list ? 493 if (!ppList) { 494 ppList = []; 495 ppList.push(listElement); 496 } else { 497 var added = false; 498 for (var i = 0; i < ppList.length; i++) { 499 if (priority < ppList[i].priority) { 500 ppList = cc.ArrayAppendObjectToIndex(ppList, listElement, i); 501 added = true; 502 break; 503 } 504 } 505 506 // Not added? priority has the higher value. Append it. 507 if (!added) { 508 ppList.push(listElement); 509 } 510 } 511 512 //update hash entry for quick access 513 var hashElement = new cc.HashUpdateEntry(ppList, listElement, target, null); 514 this._arrayForUpdates.push(hashElement); 515 this._hashForUpdates[target.__instanceId] = hashElement; 516 // this._hashForUpdates.push(hashElement); 517 518 return ppList; 519 }, 520 521 _appendIn:function (ppList, target, paused) { 522 var listElement = new cc.ListEntry(null, null, target, 0, paused, false); 523 ppList.push(listElement); 524 525 //update hash entry for quicker access 526 var hashElement = new cc.HashUpdateEntry(ppList, listElement, target, null); 527 this._arrayForUpdates.push(hashElement); 528 this._hashForUpdates[target.__instanceId] = hashElement; 529 // this._hashForUpdates.push(hashElement); 530 }, 531 532 //-----------------------public method------------------------- 533 /** 534 * <p> 535 * Modifies the time of all scheduled callbacks.<br/> 536 * You can use this property to create a 'slow motion' or 'fast forward' effect.<br/> 537 * Default is 1.0. To create a 'slow motion' effect, use values below 1.0.<br/> 538 * To create a 'fast forward' effect, use values higher than 1.0.<br/> 539 * @warning It will affect EVERY scheduled selector / action. 540 * </p> 541 * @param {Number} timeScale 542 */ 543 setTimeScale:function (timeScale) { 544 this._timeScale = timeScale; 545 }, 546 547 /** 548 * returns time scale of scheduler 549 * @return {Number} 550 */ 551 getTimeScale:function () { 552 return this._timeScale; 553 }, 554 555 /** 556 * 'update' the scheduler. (You should NEVER call this method, unless you know what you are doing.) 557 * @param {Number} dt delta time 558 */ 559 update:function (dt) { 560 this._updateHashLocked = true; 561 562 if (this._timeScale != 1.0) { 563 dt *= this._timeScale; 564 } 565 566 //Iterate all over the Updates selectors 567 var tmpEntry; 568 var i; 569 for (i = 0; i < this._updatesNegList.length; i++) { 570 tmpEntry = this._updatesNegList[i]; 571 if ((!tmpEntry.paused) && (!tmpEntry.markedForDeletion)) { 572 tmpEntry.target.update(dt); 573 } 574 } 575 576 // updates with priority == 0 577 for (i = 0; i < this._updates0List.length; i++) { 578 tmpEntry = this._updates0List[i]; 579 if ((!tmpEntry.paused) && (!tmpEntry.markedForDeletion)) { 580 tmpEntry.target.update(dt); 581 } 582 } 583 584 // updates with priority > 0 585 for (i = 0; i < this._updatesPosList.length; i++) { 586 tmpEntry = this._updatesPosList[i]; 587 if ((!tmpEntry.paused) && (!tmpEntry.markedForDeletion)) { 588 tmpEntry.target.update(dt); 589 } 590 } 591 592 //Interate all over the custom selectors 593 var elt; 594 for (i = 0; i < this._arrayForTimers.length; i++) { 595 this._currentTarget = this._arrayForTimers[i]; 596 elt = this._currentTarget; 597 this._currentTargetSalvaged = false; 598 599 if (!this._currentTarget.paused) { 600 // The 'timers' array may change while inside this loop 601 for (elt.timerIndex = 0; elt.timerIndex < elt.timers.length; elt.timerIndex++) { 602 elt.currentTimer = elt.timers[elt.timerIndex]; 603 elt.currentTimerSalvaged = false; 604 605 elt.currentTimer.update(dt); 606 elt.currentTimer = null; 607 } 608 } 609 610 if ((this._currentTargetSalvaged) && (this._currentTarget.timers.length == 0)) { 611 this._removeHashElement(this._currentTarget); 612 } 613 } 614 615 //delete all updates that are marked for deletion 616 // updates with priority < 0 617 for (i = 0; i < this._updatesNegList.length; i++) { 618 if (this._updatesNegList[i].markedForDeletion) { 619 this._removeUpdateFromHash(this._updatesNegList[i]); 620 } 621 } 622 623 // updates with priority == 0 624 for (i = 0; i < this._updates0List.length; i++) { 625 if (this._updates0List[i].markedForDeletion) { 626 this._removeUpdateFromHash(this._updates0List[i]); 627 } 628 } 629 630 // updates with priority > 0 631 for (i = 0; i < this._updatesPosList.length; i++) { 632 if (this._updatesPosList[i].markedForDeletion) { 633 this._removeUpdateFromHash(this._updatesPosList[i]); 634 } 635 } 636 637 this._updateHashLocked = false; 638 this._currentTarget = null; 639 }, 640 641 /** 642 * <p> 643 * The scheduled method will be called every 'interval' seconds.</br> 644 * If paused is YES, then it won't be called until it is resumed.<br/> 645 * If 'interval' is 0, it will be called every frame, but if so, it recommended to use 'scheduleUpdateForTarget:' instead.<br/> 646 * If the callback function is already scheduled, then only the interval parameter will be updated without re-scheduling it again.<br/> 647 * repeat let the action be repeated repeat + 1 times, use cc.REPEAT_FOREVER to let the action run continuously<br/> 648 * delay is the amount of time the action will wait before it'll start<br/> 649 * </p> 650 * @param {cc.Class} target 651 * @param {function} callback_fn 652 * @param {Number} interval 653 * @param {Number} repeat 654 * @param {Number} delay 655 * @param {Boolean} paused 656 * @example 657 * //register a schedule to scheduler 658 * cc.Director.getInstance().getScheduler().scheduleCallbackForTarget(this, function, interval, repeat, delay, !this._isRunning ); 659 */ 660 scheduleCallbackForTarget:function (target, callback_fn, interval, repeat, delay, paused) { 661 if(!callback_fn) 662 throw "cc.scheduler.scheduleCallbackForTarget(): callback_fn should be non-null."; 663 664 if(!target) 665 throw "cc.scheduler.scheduleCallbackForTarget(): target should be non-null."; 666 667 // default arguments 668 interval = interval || 0; 669 repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat; 670 delay = delay || 0; 671 paused = paused || false; 672 673 var element = this._hashForTimers[target.__instanceId]; 674 675 if (!element) { 676 // Is this the 1st element ? Then set the pause level to all the callback_fns of this target 677 element = new cc.HashTimerEntry(null, target, 0, null, null, paused, null); 678 this._arrayForTimers.push(element); 679 this._hashForTimers[target.__instanceId] = element; 680 } 681 682 var timer; 683 if (element.timers == null) { 684 element.timers = []; 685 } else { 686 for (var i = 0; i < element.timers.length; i++) { 687 timer = element.timers[i]; 688 if (callback_fn == timer._selector) { 689 cc.log("CCSheduler#scheduleCallback. Callback already scheduled. Updating interval from:" 690 + timer.getInterval().toFixed(4) + " to " + interval.toFixed(4)); 691 timer._interval = interval; 692 return; 693 } 694 } 695 } 696 697 timer = new cc.Timer(); 698 timer.initWithTarget(target, callback_fn, interval, repeat, delay); 699 element.timers.push(timer); 700 }, 701 702 /** 703 * <p> 704 * Schedules the 'update' callback_fn for a given target with a given priority.<br/> 705 * The 'update' callback_fn will be called every frame.<br/> 706 * The lower the priority, the earlier it is called. 707 * </p> 708 * @param {cc.Class} target 709 * @param {Number} priority 710 * @param {Boolean} paused 711 * @example 712 * //register this object to scheduler 713 * cc.Director.getInstance().getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning ); 714 */ 715 scheduleUpdateForTarget:function (target, priority, paused) { 716 var hashElement = this._hashForUpdates[target.__instanceId]; 717 718 if (hashElement) { 719 // TODO: check if priority has changed! 720 hashElement.entry.markedForDeletion = false; 721 return; 722 } 723 724 // most of the updates are going to be 0, that's way there 725 // is an special list for updates with priority 0 726 if (priority == 0) { 727 this._appendIn(this._updates0List, target, paused); 728 } else if (priority < 0) { 729 this._updatesNegList = this._priorityIn(this._updatesNegList, target, priority, paused); 730 } else { 731 // priority > 0 732 this._updatesPosList = this._priorityIn(this._updatesPosList, target, priority, paused); 733 } 734 }, 735 736 /** 737 * <p> 738 * Unschedule a callback function for a given target.<br/> 739 * If you want to unschedule the "update", use unscheudleUpdateForTarget. 740 * </p> 741 * @param {cc.Class} target 742 * @param {function} callback_fn 743 * @example 744 * //unschedule a selector of target 745 * cc.Director.getInstance().getScheduler().unscheduleCallbackForTarget(function, this); 746 */ 747 unscheduleCallbackForTarget:function (target, callback_fn) { 748 // explicity handle nil arguments when removing an object 749 if ((target == null) || (callback_fn == null)) { 750 return; 751 } 752 753 var element = this._hashForTimers[target.__instanceId]; 754 if (element != null) { 755 for (var i = 0; i < element.timers.length; i++) { 756 var timer = element.timers[i]; 757 if (callback_fn == timer._selector) { 758 if ((timer == element.currentTimer) && (!element.currentTimerSalvaged)) { 759 element.currentTimerSalvaged = true; 760 } 761 cc.ArrayRemoveObjectAtIndex(element.timers, i); 762 //update timerIndex in case we are in tick;, looping over the actions 763 if (element.timerIndex >= i) { 764 element.timerIndex--; 765 } 766 767 if (element.timers.length == 0) { 768 if (this._currentTarget == element) { 769 this._currentTargetSalvaged = true; 770 } else { 771 772 this._removeHashElement(element); 773 } 774 } 775 return; 776 } 777 } 778 } 779 }, 780 781 /** 782 * Unschedules the update callback function for a given target 783 * @param {cc.Class} target 784 * @example 785 * //unschedules the "update" method. 786 * cc.Director.getInstance().getScheduler().unscheduleUpdateForTarget(this); 787 */ 788 unscheduleUpdateForTarget:function (target) { 789 if (target == null) { 790 return; 791 } 792 793 var element = this._hashForUpdates[target.__instanceId]; 794 if (element != null) { 795 if (this._updateHashLocked) { 796 element.entry.markedForDeletion = true; 797 } else { 798 this._removeUpdateFromHash(element.entry); 799 } 800 } 801 }, 802 803 /** 804 * Unschedules all function callbacks for a given target. This also includes the "update" callback function. 805 * @param {cc.Class} target 806 */ 807 unscheduleAllCallbacksForTarget:function (target) { 808 //explicit NULL handling 809 if (target == null) { 810 return; 811 } 812 813 var element = this._hashForTimers[target.__instanceId]; 814 if (element) { 815 if ((!element.currentTimerSalvaged) && (cc.ArrayContainsObject(element.timers, element.currentTimer))) { 816 element.currentTimerSalvaged = true; 817 } 818 element.timers.length = 0; 819 820 if (this._currentTarget == element) { 821 this._currentTargetSalvaged = true; 822 } else { 823 this._removeHashElement(element); 824 } 825 } 826 // update selector 827 this.unscheduleUpdateForTarget(target); 828 }, 829 830 /** 831 * <p> 832 * Unschedules all function callbacks from all targets. <br/> 833 * You should NEVER call this method, unless you know what you are doing. 834 * </p> 835 */ 836 unscheduleAllCallbacks:function () { 837 this.unscheduleAllCallbacksWithMinPriority(cc.PRIORITY_SYSTEM); 838 }, 839 840 /** 841 * <p> 842 * Unschedules all function callbacks from all targets with a minimum priority.<br/> 843 * You should only call this with kCCPriorityNonSystemMin or higher. 844 * </p> 845 * @param {Number} minPriority 846 */ 847 unscheduleAllCallbacksWithMinPriority:function (minPriority) { 848 // Custom Selectors 849 var i; 850 for (i = 0; i < this._arrayForTimers.length; i++) { 851 // element may be removed in unscheduleAllCallbacksForTarget 852 this.unscheduleAllCallbacksForTarget(this._arrayForTimers[i].target); 853 } 854 855 //updates selectors 856 if (minPriority < 0) { 857 for (i = 0; i < this._updatesNegList.length; i++) { 858 this.unscheduleUpdateForTarget(this._updatesNegList[i].target); 859 } 860 } 861 862 if (minPriority <= 0) { 863 for (i = 0; i < this._updates0List.length; i++) { 864 this.unscheduleUpdateForTarget(this._updates0List[i].target); 865 } 866 } 867 868 for (i = 0; i < this._updatesPosList.length; i++) { 869 if (this._updatesPosList[i].priority >= minPriority) { 870 this.unscheduleUpdateForTarget(this._updatesPosList[i].target); 871 } 872 } 873 }, 874 875 /** 876 * <p> 877 * Pause all selectors from all targets.<br/> 878 * You should NEVER call this method, unless you know what you are doing. 879 * </p> 880 */ 881 pauseAllTargets:function () { 882 return this.pauseAllTargetsWithMinPriority(cc.PRIORITY_SYSTEM); 883 }, 884 885 /** 886 * Pause all selectors from all targets with a minimum priority. <br/> 887 * You should only call this with kCCPriorityNonSystemMin or higher. 888 * @param minPriority 889 */ 890 pauseAllTargetsWithMinPriority:function (minPriority) { 891 var idsWithSelectors = []; 892 893 var i, element; 894 // Custom Selectors 895 for (i = 0; i < this._arrayForTimers.length; i++) { 896 element = this._arrayForTimers[i]; 897 if (element) { 898 element.paused = true; 899 idsWithSelectors.push(element.target); 900 } 901 } 902 903 // Updates selectors 904 if (minPriority < 0) { 905 for (i = 0; i < this._updatesNegList.length; i++) { 906 element = this._updatesNegList[i]; 907 if (element) { 908 element.paused = true; 909 idsWithSelectors.push(element.target); 910 } 911 } 912 } 913 914 if (minPriority <= 0) { 915 for (i = 0; i < this._updates0List.length; i++) { 916 element = this._updates0List[i]; 917 if (element) { 918 element.paused = true; 919 idsWithSelectors.push(element.target); 920 } 921 } 922 } 923 924 for (i = 0; i < this._updatesPosList.length; i++) { 925 element = this._updatesPosList[i]; 926 if (element) { 927 element.paused = true; 928 idsWithSelectors.push(element.target); 929 } 930 } 931 932 return idsWithSelectors; 933 }, 934 935 /** 936 * Resume selectors on a set of targets.<br/> 937 * This can be useful for undoing a call to pauseAllCallbacks. 938 * @param targetsToResume 939 */ 940 resumeTargets:function (targetsToResume) { 941 if (!targetsToResume) 942 return; 943 944 for (var i = 0; i < targetsToResume.length; i++) { 945 this.resumeTarget(targetsToResume[i]); 946 } 947 }, 948 949 /** 950 * <p> 951 * Pauses the target.<br/> 952 * All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.<br/> 953 * If the target is not present, nothing happens. 954 * </p> 955 * @param {cc.Class} target 956 */ 957 pauseTarget:function (target) { 958 if(!target) 959 throw "cc.Scheduler.pauseTarget():target should be non-null"; 960 961 //customer selectors 962 var element = this._hashForTimers[target.__instanceId]; 963 if (element) { 964 element.paused = true; 965 } 966 967 //update selector 968 var elementUpdate = this._hashForUpdates[target.__instanceId]; 969 if (elementUpdate) { 970 elementUpdate.entry.paused = true; 971 } 972 }, 973 974 /** 975 * Resumes the target.<br/> 976 * The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again.<br/> 977 * If the target is not present, nothing happens. 978 * @param {cc.Class} target 979 */ 980 resumeTarget:function (target) { 981 if(!target) 982 throw "cc.Scheduler.resumeTarget():target should be non-null"; 983 984 // custom selectors 985 var element = this._hashForTimers[target.__instanceId]; 986 987 if (element) { 988 element.paused = false; 989 } 990 991 //update selector 992 var elementUpdate = this._hashForUpdates[target.__instanceId]; 993 994 if (elementUpdate) { 995 elementUpdate.entry.paused = false; 996 } 997 }, 998 999 /** 1000 * Returns whether or not the target is paused 1001 * @param {cc.Class} target 1002 * @return {Boolean} 1003 */ 1004 isTargetPaused:function (target) { 1005 if(!target) 1006 throw "cc.Scheduler.isTargetPaused():target should be non-null"; 1007 1008 // Custom selectors 1009 var element = this._hashForTimers[target.__instanceId]; 1010 if (element) { 1011 return element.paused; 1012 } 1013 return false; 1014 } 1015 }); 1016 1017