CCScheduler.js 32 KB

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