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