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  * <p> An interval action is an action that takes place within a certain period of time. <br/>
 29  * It has an start time, and a finish time. The finish time is the parameter<br/>
 30  * duration plus the start time.</p>
 31  *
 32  * <p>These CCActionInterval actions have some interesting properties, like:<br/>
 33  * - They can run normally (default)  <br/>
 34  * - They can run reversed with the reverse method   <br/>
 35  * - They can run with the time altered with the Accelerate, AccelDeccel and Speed actions. </p>
 36  *
 37  * <p>For example, you can simulate a Ping Pong effect running the action normally and<br/>
 38  * then running it again in Reverse mode. </p>
 39  *
 40  * @class
 41  * @extends cc.FiniteTimeAction
 42  * @Example
 43  * // example
 44  * var pingPongAction = cc.Sequence.create(action, action.reverse());
 45  */
 46 cc.ActionInterval = cc.FiniteTimeAction.extend(/** @lends cc.ActionInterval# */{
 47     _elapsed:0,
 48     _firstTick:false,
 49 
 50     ctor:function () {
 51         cc.FiniteTimeAction.prototype.ctor.call(this);
 52         this._elapsed = 0;
 53         this._firstTick = false;
 54     },
 55 
 56     /** how many seconds had elapsed since the actions started to run.
 57      * @return {Number}
 58      */
 59     getElapsed:function () {
 60         return this._elapsed;
 61     },
 62 
 63     /** initializes the action
 64      * @param {Number} d duration in seconds
 65      * @return {Boolean}
 66      */
 67     initWithDuration:function (d) {
 68         this._duration = (d === 0) ? cc.FLT_EPSILON : d;
 69         // prevent division by 0
 70         // This comparison could be in step:, but it might decrease the performance
 71         // by 3% in heavy based action games.
 72         this._elapsed = 0;
 73         this._firstTick = true;
 74         return true;
 75     },
 76 
 77     /** returns true if the action has finished
 78      * @return {Boolean}
 79      */
 80     isDone:function () {
 81         return (this._elapsed >= this._duration);
 82     },
 83 
 84     /**
 85      * returns a new clone of the action
 86      * @returns {cc.ActionInterval}
 87      */
 88     clone:function () {
 89         var action = new cc.ActionInterval();
 90         action.initWithDuration(this._duration);
 91         return action;
 92     },
 93 
 94     /**
 95      * @param {Number} dt delta time in seconds
 96      */
 97     step:function (dt) {
 98         if (this._firstTick) {
 99             this._firstTick = false;
100             this._elapsed = 0;
101         } else
102             this._elapsed += dt;
103 
104         //this.update((1 > (this._elapsed / this._duration)) ? this._elapsed / this._duration : 1);
105         //this.update(Math.max(0, Math.min(1, this._elapsed / Math.max(this._duration, cc.FLT_EPSILON))));
106         var t = this._elapsed / (this._duration > 0.0000001192092896 ? this._duration : 0.0000001192092896);
107         t = (1 > t ? t : 1);
108         this.update(t > 0 ? t : 0);
109     },
110 
111     /**
112      * @param {cc.Node} target
113      */
114     startWithTarget:function (target) {
115         cc.Action.prototype.startWithTarget.call(this, target);
116         this._elapsed = 0;
117         this._firstTick = true;
118     },
119 
120     /**
121      * @return {Null}
122      */
123     reverse:function () {
124         cc.log("cc.IntervalAction: reverse not implemented.");
125         return null;
126     },
127 
128     /**
129      * @param {Number} amp
130      */
131     setAmplitudeRate:function (amp) {
132         // Abstract class needs implementation
133         cc.log("cc.ActionInterval.setAmplitudeRate(): it should be overridden in subclass.");
134     },
135 
136     /**
137      * @return {Number}
138      */
139     getAmplitudeRate:function () {
140         // Abstract class needs implementation
141         cc.log("cc.ActionInterval.getAmplitudeRate(): it should be overridden in subclass.");
142     }
143 });
144 
145 /**
146  * @param {Number} d duration in seconds
147  * @return {cc.ActionInterval}
148  * @example
149  * // example
150  * var actionInterval = cc.ActionInterval.create(3);
151  */
152 cc.ActionInterval.create = function (d) {
153     var action = new cc.ActionInterval();
154     action.initWithDuration(d);
155     return action;
156 };
157 
158 
159 /** Runs actions sequentially, one after another
160  * @class
161  * @extends cc.ActionInterval
162  */
163 cc.Sequence = cc.ActionInterval.extend(/** @lends cc.Sequence# */{
164     _actions:null,
165     _split:null,
166     _last:0,
167 
168     /**
169      * Constructor
170      */
171     ctor:function () {
172         cc.ActionInterval.prototype.ctor.call(this);
173         this._actions = [];
174         this._split = null;
175         this._last = 0;
176     },
177 
178     /** initializes the action <br/>
179      * @param {cc.FiniteTimeAction} actionOne
180      * @param {cc.FiniteTimeAction} actionTwo
181      * @return {Boolean}
182      */
183     initWithTwoActions:function (actionOne, actionTwo) {
184         if(!actionOne || !actionTwo)
185             throw "cc.Sequence.initWithTwoActions(): arguments must all be non nil";
186 
187         var d = actionOne.getDuration() + actionTwo.getDuration();
188         this.initWithDuration(d);
189 
190         this._actions[0] = actionOne;
191         this._actions[1] = actionTwo;
192         return true;
193     },
194 
195     /**
196      * returns a new clone of the action
197      * @returns {cc.Sequence}
198      */
199     clone:function () {
200         var action = new cc.Sequence();
201         action.initWithTwoActions(this._actions[0].clone(), this._actions[1].clone());
202         return action;
203     },
204 
205     /**
206      * @param {cc.Node} target
207      */
208     startWithTarget:function (target) {
209         cc.ActionInterval.prototype.startWithTarget.call(this, target);
210         this._split = this._actions[0].getDuration() / this._duration;
211         this._last = -1;
212     },
213 
214     /**
215      * stop the action
216      */
217     stop:function () {
218         // Issue #1305
219         if (this._last !== -1)
220             this._actions[this._last].stop();
221         cc.Action.prototype.stop.call(this);
222     },
223 
224     /**
225      * @param {Number} time  time in seconds
226      */
227     update:function (time) {
228         var new_t, found = 0;
229         var locSplit = this._split, locActions = this._actions, locLast = this._last;
230         if (time < locSplit) {
231             // action[0]
232             new_t = (locSplit !== 0) ? time / locSplit : 1;
233 
234             if (found === 0 && locLast === 1) {
235                 // Reverse mode ?
236                 // XXX: Bug. this case doesn't contemplate when _last==-1, found=0 and in "reverse mode"
237                 // since it will require a hack to know if an action is on reverse mode or not.
238                 // "step" should be overriden, and the "reverseMode" value propagated to inner Sequences.
239                 locActions[1].update(0);
240                 locActions[1].stop();
241             }
242         } else {
243             // action[1]
244             found = 1;
245             new_t = (locSplit === 1) ? 1 : (time - locSplit) / (1 - locSplit);
246 
247             if (locLast === -1) {
248                 // action[0] was skipped, execute it.
249                 locActions[0].startWithTarget(this._target);
250                 locActions[0].update(1);
251                 locActions[0].stop();
252             }
253             if (!locLast) {
254                 // switching to action 1. stop action 0.
255                 locActions[0].update(1);
256                 locActions[0].stop();
257             }
258         }
259 
260         // Last action found and it is done.
261         if (locLast === found && locActions[found].isDone())
262             return;
263 
264         // Last action found and it is done
265         if (locLast !== found)
266             locActions[found].startWithTarget(this._target);
267 
268         locActions[found].update(new_t);
269         this._last = found;
270     },
271 
272     /**
273      * @return {cc.ActionInterval}
274      */
275     reverse:function () {
276         return cc.Sequence._actionOneTwo(this._actions[1].reverse(), this._actions[0].reverse());
277     },
278 
279     /**
280      * to copy object with deep copy.
281      * @return {object}
282      */
283     copy:function () {
284         return this.clone();
285     }
286 });
287 /** helper constructor to create an array of sequenceable actions
288  * @param {Array|cc.FiniteTimeAction} tempArray
289  * @return {cc.Sequence}
290  * @example
291  * // example
292  * // create sequence with actions
293  * var seq = cc.Sequence.create(act1, act2);
294  *
295  * // create sequence with array
296  * var seq = cc.Sequence.create(actArray);
297  */
298 cc.Sequence.create = function (/*Multiple Arguments*/tempArray) {
299     var paraArray = (tempArray instanceof Array) ? tempArray : arguments;
300     if ((paraArray.length > 0) && (paraArray[paraArray.length - 1] == null))
301         cc.log("parameters should not be ending with null in Javascript");
302 
303     var prev = paraArray[0];
304     for (var i = 1; i < paraArray.length; i++) {
305         if (paraArray[i])
306             prev = cc.Sequence._actionOneTwo(prev, paraArray[i]);
307     }
308     return prev;
309 };
310 
311 /** creates the action
312  * @param {cc.FiniteTimeAction} actionOne
313  * @param {cc.FiniteTimeAction} actionTwo
314  * @return {cc.Sequence}
315  * @private
316  */
317 cc.Sequence._actionOneTwo = function (actionOne, actionTwo) {
318     var sequence = new cc.Sequence();
319     sequence.initWithTwoActions(actionOne, actionTwo);
320     return sequence;
321 };
322 
323 
324 /** Repeats an action a number of times.
325  * To repeat an action forever use the CCRepeatForever action.
326  * @class
327  * @extends cc.ActionInterval
328  */
329 cc.Repeat = cc.ActionInterval.extend(/** @lends cc.Repeat# */{
330     _times:0,
331     _total:0,
332     _nextDt:0,
333     _actionInstant:false,
334     _innerAction:null, //CCFiniteTimeAction
335 
336     ctor:function () {
337         cc.ActionInterval.prototype.ctor.call(this);
338         this._times = 0;
339         this._total = 0;
340         this._nextDt = 0;
341         this._actionInstant = false;
342         this._innerAction = null;
343     },
344 
345     /**
346      * @param {cc.FiniteTimeAction} action
347      * @param {Number} times
348      * @return {Boolean}
349      */
350     initWithAction:function (action, times) {
351         var duration = action.getDuration() * times;
352 
353         if (this.initWithDuration(duration)) {
354             this._times = times;
355             this._innerAction = action;
356             if (action instanceof cc.ActionInstant)
357                 this._times -= 1;
358             this._total = 0;
359             return true;
360         }
361         return false;
362     },
363 
364     /**
365      * returns a new clone of the action
366      * @returns {cc.Repeat}
367      */
368     clone:function () {
369         var action = new cc.Repeat();
370         action.initWithAction(this._innerAction.clone(), this._times);
371         return action;
372     },
373 
374     /**
375      * @param {cc.Node} target
376      */
377     startWithTarget:function (target) {
378         this._total = 0;
379         this._nextDt = this._innerAction.getDuration() / this._duration;
380         cc.ActionInterval.prototype.startWithTarget.call(this, target);
381         this._innerAction.startWithTarget(target);
382     },
383 
384     /**
385      * stop the action
386      */
387     stop:function () {
388         this._innerAction.stop();
389         cc.Action.prototype.stop.call(this);
390     },
391 
392     /**
393      * @param {Number} time time in seconds
394      */
395     update:function (time) {
396         var locInnerAction = this._innerAction;
397         var locDuration = this._duration;
398         var locTimes = this._times;
399         var locNextDt = this._nextDt;
400 
401         if (time >= locNextDt) {
402             while (time > locNextDt && this._total < locTimes) {
403                 locInnerAction.update(1);
404                 this._total++;
405                 locInnerAction.stop();
406                 locInnerAction.startWithTarget(this._target);
407                 locNextDt += locInnerAction.getDuration() / locDuration;
408                 this._nextDt = locNextDt;
409             }
410 
411             // fix for issue #1288, incorrect end value of repeat
412             if (time >= 1.0 && this._total < locTimes)
413                 this._total++;
414 
415             // don't set a instantaction back or update it, it has no use because it has no duration
416             if (this._actionInstant) {
417                 if (this._total == locTimes) {
418                     locInnerAction.update(1);
419                     locInnerAction.stop();
420                 } else {
421                     // issue #390 prevent jerk, use right update
422                     locInnerAction.update(time - (locNextDt - locInnerAction.getDuration() / locDuration));
423                 }
424             }
425         } else {
426             locInnerAction.update((time * locTimes) % 1.0);
427         }
428     },
429 
430     /**
431      * @return {Boolean}
432      */
433     isDone:function () {
434         return this._total == this._times;
435     },
436 
437     /**
438      * @return {cc.ActionInterval}
439      */
440     reverse:function () {
441         return cc.Repeat.create(this._innerAction.reverse(), this._times);
442     },
443 
444     /**
445      * @param {cc.FiniteTimeAction} action
446      */
447     setInnerAction:function (action) {
448         if (this._innerAction != action) {
449             this._innerAction = action;
450         }
451     },
452 
453     /**
454      * @return {cc.FiniteTimeAction}
455      */
456     getInnerAction:function () {
457         return this._innerAction;
458     }
459 });
460 /** creates a CCRepeat action. Times is an unsigned integer between 1 and pow(2,30)
461  * @param {cc.FiniteTimeAction} action
462  * @param {Number} times
463  * @return {cc.Repeat}
464  * @example
465  * // example
466  * var rep = cc.Repeat.create(cc.Sequence.create(jump2, jump1), 5);
467  */
468 cc.Repeat.create = function (action, times) {
469     var repeat = new cc.Repeat();
470     repeat.initWithAction(action, times);
471     return repeat;
472 };
473 
474 
475 /**  Repeats an action for ever.  <br/>
476  * To repeat the an action for a limited number of times use the Repeat action. <br/>
477  * @warning This action can't be Sequencable because it is not an IntervalAction
478  * @class
479  * @extends cc.ActionInterval
480  */
481 
482 cc.RepeatForever = cc.ActionInterval.extend(/** @lends cc.RepeatForever# */{
483     _innerAction:null, //CCActionInterval
484 
485     ctor:function () {
486         cc.ActionInterval.prototype.ctor.call(this);
487         this._innerAction = null;
488     },
489 
490     /**
491      * @param {cc.ActionInterval} action
492      * @return {Boolean}
493      */
494     initWithAction:function (action) {
495         if(!action)
496             throw "cc.RepeatForever.initWithAction(): action must be non null";
497 
498         this._innerAction = action;
499         return true;
500     },
501 
502     /**
503      * returns a new clone of the action
504      * @returns {cc.RepeatForever}
505      */
506     clone:function () {
507         var action = new cc.RepeatForever();
508         action.initWithAction(this._innerAction.clone());
509         return action;
510     },
511 
512     /**
513      * @param {cc.Node} target
514      */
515     startWithTarget:function (target) {
516         cc.ActionInterval.prototype.startWithTarget.call(this, target);
517         this._innerAction.startWithTarget(target);
518     },
519 
520     /**
521      * @param dt delta time in seconds
522      */
523     step:function (dt) {
524         var locInnerAction = this._innerAction;
525         locInnerAction.step(dt);
526         if (locInnerAction.isDone()) {
527             //var diff = locInnerAction.getElapsed() - locInnerAction.getDuration();
528             locInnerAction.startWithTarget(this._target);
529             // to prevent jerk. issue #390 ,1247
530             //this._innerAction.step(0);
531             //this._innerAction.step(diff);
532             locInnerAction.step(locInnerAction.getElapsed() - locInnerAction.getDuration());
533         }
534     },
535 
536     /**
537      * @return {Boolean}
538      */
539     isDone:function () {
540         return false;
541     },
542 
543     /**
544      * @return {cc.ActionInterval}
545      */
546     reverse:function () {
547         return (cc.RepeatForever.create(this._innerAction.reverse()));
548     },
549 
550     /**
551      *
552      * @param {cc.ActionInterval} action
553      */
554     setInnerAction:function (action) {
555         if (this._innerAction != action) {
556             this._innerAction = action;
557         }
558     },
559 
560     /**
561      * @return {cc.ActionInterval}
562      */
563     getInnerAction:function () {
564         return this._innerAction;
565     }
566 });
567 /**
568  * Repeat the acton forever
569  * @param action
570  * @return {cc.RepeatForever}
571  * @example
572  * // example
573  * var repeat = cc.RepeatForever.create(cc.RotateBy.create(1.0, 360));
574  */
575 cc.RepeatForever.create = function (action) {
576     var ret = new cc.RepeatForever();
577     if (ret && ret.initWithAction(action))
578         return ret;
579     return null;
580 };
581 
582 
583 /** Spawn a new action immediately
584  * @class
585  * @extends cc.ActionInterval
586  */
587 cc.Spawn = cc.ActionInterval.extend(/** @lends cc.Spawn# */{
588     _one:null,
589     _two:null,
590 
591     ctor:function () {
592         cc.ActionInterval.prototype.ctor.call(this);
593         this._one = null;
594         this._two = null;
595     },
596 
597     /** initializes the Spawn action with the 2 actions to spawn
598      * @param {cc.FiniteTimeAction} action1
599      * @param {cc.FiniteTimeAction} action2
600      * @return {Boolean}
601      */
602     initWithTwoActions:function (action1, action2) {
603         if(!action1 || !action2)
604             throw "cc.Spawn.initWithTwoActions(): arguments must all be non null" ;
605 
606         var ret = false;
607 
608         var d1 = action1.getDuration();
609         var d2 = action2.getDuration();
610 
611         if (this.initWithDuration(Math.max(d1, d2))) {
612             this._one = action1;
613             this._two = action2;
614 
615             if (d1 > d2) {
616                 this._two = cc.Sequence._actionOneTwo(action2, cc.DelayTime.create(d1 - d2));
617             } else if (d1 < d2) {
618                 this._one = cc.Sequence._actionOneTwo(action1, cc.DelayTime.create(d2 - d1));
619             }
620 
621             ret = true;
622         }
623         return ret;
624     },
625 
626     /**
627      * returns a new clone of the action
628      * @returns {cc.Spawn}
629      */
630     clone:function () {
631         var action = new cc.Spawn();
632         action.initWithTwoActions(this._one.clone(), this._two.clone());
633         return action;
634     },
635 
636     /**
637      * @param {cc.Node} target
638      */
639     startWithTarget:function (target) {
640         cc.ActionInterval.prototype.startWithTarget.call(this, target);
641         this._one.startWithTarget(target);
642         this._two.startWithTarget(target);
643     },
644 
645     /**
646      * Stop the action
647      */
648     stop:function () {
649         this._one.stop();
650         this._two.stop();
651         cc.Action.prototype.stop.call(this);
652     },
653 
654     /**
655      * @param {Number} time time in seconds
656      */
657     update:function (time) {
658         if (this._one)
659             this._one.update(time);
660         if (this._two)
661             this._two.update(time);
662     },
663 
664     /**
665      * @return {cc.FiniteTimeAction}
666      */
667     reverse:function () {
668         return cc.Spawn._actionOneTwo(this._one.reverse(), this._two.reverse());
669     }
670 });
671 
672 /**
673  * @param {Array|cc.FiniteTimeAction}tempArray
674  * @return {cc.FiniteTimeAction}
675  * @example
676  * // example
677  * var action = cc.Spawn.create(cc.JumpBy.create(2, cc.p(300, 0), 50, 4), cc.RotateBy.create(2, 720));
678  */
679 cc.Spawn.create = function (/*Multiple Arguments*/tempArray) {
680     var paramArray = (tempArray instanceof Array) ? tempArray : arguments;
681     if ((paramArray.length > 0) && (paramArray[paramArray.length - 1] == null))
682         cc.log("parameters should not be ending with null in Javascript");
683 
684     var prev = paramArray[0];
685     for (var i = 1; i < paramArray.length; i++) {
686         if (paramArray[i] != null)
687             prev = this._actionOneTwo(prev, paramArray[i]);
688     }
689     return prev;
690 };
691 
692 /**
693  * @param {cc.FiniteTimeAction} action1
694  * @param {cc.FiniteTimeAction} action2
695  * @return {cc.Spawn}
696  * @private
697  */
698 cc.Spawn._actionOneTwo = function (action1, action2) {
699     var pSpawn = new cc.Spawn();
700     pSpawn.initWithTwoActions(action1, action2);
701     return pSpawn;
702 };
703 
704 
705 /** Rotates a cc.Node object to a certain angle by modifying it's
706  * rotation attribute. <br/>
707  * The direction will be decided by the shortest angle.
708  * @class
709  * @extends cc.ActionInterval
710  */
711 cc.RotateTo = cc.ActionInterval.extend(/** @lends cc.RotateTo# */{
712     _dstAngleX:0,
713     _startAngleX:0,
714     _diffAngleX:0,
715 
716     _dstAngleY:0,
717     _startAngleY:0,
718     _diffAngleY:0,
719 
720     ctor:function () {
721         cc.ActionInterval.prototype.ctor.call(this);
722         this._dstAngleX = 0;
723         this._startAngleX = 0;
724         this._diffAngleX = 0;
725 
726         this._dstAngleY = 0;
727         this._startAngleY = 0;
728         this._diffAngleY = 0;
729     },
730 
731     /**
732      * @param {Number} duration
733      * @param {Number} deltaAngleX
734      * @param {Number} deltaAngleY
735      * @return {Boolean}
736      */
737     initWithDuration:function (duration, deltaAngleX, deltaAngleY) {
738         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
739             this._dstAngleX = deltaAngleX || 0;
740             this._dstAngleY = deltaAngleY || this._dstAngleX;
741             return true;
742         }
743         return false;
744     },
745 
746     /**
747      * returns a new clone of the action
748      * @returns {cc.RotateTo}
749      */
750     clone:function () {
751         var action = new cc.RotateTo();
752         action.initWithDuration(this._duration, this._dstAngleX, this._dstAngleY);
753         return action;
754     },
755 
756     /**
757      * @param {cc.Node} target
758      */
759     startWithTarget:function (target) {
760         cc.ActionInterval.prototype.startWithTarget.call(this, target);
761 
762         // Calculate X
763         var locStartAngleX = target.getRotationX() % 360.0;
764         var locDiffAngleX = this._dstAngleX - locStartAngleX;
765         if (locDiffAngleX > 180)
766             locDiffAngleX -= 360;
767         if (locDiffAngleX < -180)
768             locDiffAngleX += 360;
769         this._startAngleX = locStartAngleX;
770         this._diffAngleX = locDiffAngleX;
771 
772         // Calculate Y  It's duplicated from calculating X since the rotation wrap should be the same
773         this._startAngleY = target.getRotationY() % 360.0;
774         var locDiffAngleY = this._dstAngleY - this._startAngleY;
775         if (locDiffAngleY > 180)
776             locDiffAngleY -= 360;
777         if (locDiffAngleY < -180)
778             locDiffAngleY += 360;
779         this._diffAngleY = locDiffAngleY
780     },
781 
782     /**
783      * RotateTo reverse not implemented
784      */
785     reverse:function () {
786         cc.log("cc.RotateTo.reverse(): it should be overridden in subclass.");
787     },
788 
789     /**
790      * @param {Number} time time in seconds
791      */
792     update:function (time) {
793         if (this._target) {
794             this._target.setRotationX(this._startAngleX + this._diffAngleX * time);
795             this._target.setRotationY(this._startAngleY + this._diffAngleY * time);
796         }
797     }
798 });
799 
800 /**
801  * creates the action with separate rotation angles
802  * @param {Number} duration duration in seconds
803  * @param {Number} deltaAngleX deltaAngleX in degrees.
804  * @param {Number} [deltaAngleY=] deltaAngleY in degrees.
805  * @return {cc.RotateTo}
806  * @example
807  * // example
808  * var rotateTo = cc.RotateTo.create(2, 61.0);
809  */
810 cc.RotateTo.create = function (duration, deltaAngleX, deltaAngleY) {
811     var rotateTo = new cc.RotateTo();
812     rotateTo.initWithDuration(duration, deltaAngleX, deltaAngleY);
813     return rotateTo;
814 };
815 
816 
817 /** Rotates a cc.Node object clockwise a number of degrees by modifying it's rotation attribute.
818  * @class
819  * @extends  cc.ActionInterval
820  */
821 cc.RotateBy = cc.ActionInterval.extend(/** @lends cc.RotateBy# */{
822     _angleX:0,
823     _startAngleX:0,
824     _angleY:0,
825     _startAngleY:0,
826 
827     ctor:function () {
828         cc.ActionInterval.prototype.ctor.call(this);
829         this._angleX = 0;
830         this._startAngleX = 0;
831         this._angleY = 0;
832         this._startAngleY = 0;
833     },
834 
835     /**
836      * @param {Number} duration duration in seconds
837      * @param {Number} deltaAngleX deltaAngleX in degrees
838      * @param {Number} [deltaAngleY=] deltaAngleY in degrees
839      * @return {Boolean}
840      */
841     initWithDuration:function (duration, deltaAngleX, deltaAngleY) {
842         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
843             this._angleX = deltaAngleX || 0;
844             this._angleY = deltaAngleY || this._angleX;
845             return true;
846         }
847         return false;
848     },
849 
850     /**
851      * returns a new clone of the action
852      * @returns {cc.RotateBy}
853      */
854     clone:function () {
855         var action = new cc.RotateBy();
856         action.initWithDuration(this._duration, this._angleX, this._angleY);
857         return action;
858     },
859 
860     /**
861      * @param {cc.Node} target
862      */
863     startWithTarget:function (target) {
864         cc.ActionInterval.prototype.startWithTarget.call(this, target);
865         this._startAngleX = target.getRotationX();
866         this._startAngleY = target.getRotationY();
867     },
868 
869     /**
870      * @param {Number} time
871      */
872     update:function (time) {
873         if (this._target) {
874             this._target.setRotationX(this._startAngleX + this._angleX * time);
875             this._target.setRotationY(this._startAngleY + this._angleY * time);
876         }
877     },
878 
879     /**
880      * @return {cc.ActionInterval}
881      */
882     reverse:function () {
883         return cc.RotateBy.create(this._duration, -this._angleX, -this._angleY);
884     }
885 });
886 
887 /**
888  * @param {Number} duration druation in seconds
889  * @param {Number} deltaAngleX deltaAngleX in degrees
890  * @param {Number} [deltaAngleY=] deltaAngleY in degrees
891  * @return {cc.RotateBy}
892  * @example
893  * // example
894  * var actionBy = cc.RotateBy.create(2, 360);
895  */
896 cc.RotateBy.create = function (duration, deltaAngleX, deltaAngleY) {
897     var rotateBy = new cc.RotateBy();
898     rotateBy.initWithDuration(duration, deltaAngleX, deltaAngleY);
899     return rotateBy;
900 };
901 
902 
903 /**
904  * <p>
905  *     Moves a CCNode object x,y pixels by modifying it's position attribute.                                  <br/>
906  *     x and y are relative to the position of the object.                                                     <br/>
907  *     Several CCMoveBy actions can be concurrently called, and the resulting                                  <br/>
908  *     movement will be the sum of individual movements.
909  * </p>
910  * @class
911  * @extends cc.ActionInterval
912  */
913 cc.MoveBy = cc.ActionInterval.extend(/** @lends cc.MoveBy# */{
914     _positionDelta:null,
915     _startPosition:null,
916     _previousPosition:null,
917 
918     ctor:function () {
919         cc.ActionInterval.prototype.ctor.call(this);
920 
921         this._positionDelta = cc.p(0, 0);
922         this._startPosition = cc.p(0, 0);
923         this._previousPosition = cc.p(0, 0);
924     },
925 
926     /**
927      * @param {Number} duration duration in seconds
928      * @param {cc.Point} position
929      * @return {Boolean}
930      */
931     initWithDuration:function (duration, position) {
932         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
933             this._positionDelta.x = position.x;
934             this._positionDelta.y = position.y;
935             return true;
936         }
937         return false;
938     },
939 
940     /**
941      * returns a new clone of the action
942      * @returns {cc.MoveBy}
943      */
944     clone:function () {
945         var action = new cc.MoveBy();
946         action.initWithDuration(this._duration, this._positionDelta)
947         return action;
948     },
949 
950     /**
951      * @param {Number} target
952      */
953     startWithTarget:function (target) {
954         cc.ActionInterval.prototype.startWithTarget.call(this, target);
955         var locPosX = target.getPositionX();
956         var locPosY = target.getPositionY();
957         this._previousPosition.x = locPosX;
958         this._previousPosition.y = locPosY;
959         this._startPosition.x = locPosX;
960         this._startPosition.y = locPosY;
961     },
962 
963     /**
964      * @param {Number} time time in seconds
965      */
966     update:function (time) {
967         if (this._target) {
968             var x = this._positionDelta.x * time;
969             var y = this._positionDelta.y * time;
970             var locStartPosition = this._startPosition;
971             if (cc.ENABLE_STACKABLE_ACTIONS) {
972                 var targetX = this._target.getPositionX();
973                 var targetY = this._target.getPositionY();
974                 var locPreviousPosition = this._previousPosition;
975 
976                 locStartPosition.x = locStartPosition.x + targetX - locPreviousPosition.x;
977                 locStartPosition.y = locStartPosition.y + targetY - locPreviousPosition.y;
978                 x = x + locStartPosition.x;
979                 y = y + locStartPosition.y;
980 
981                 this._target.setPosition(x, y);
982                 locPreviousPosition.x = x;
983                 locPreviousPosition.y = y;
984             } else {
985                 this._target.setPosition(locStartPosition.x + x, locStartPosition.y + y);
986             }
987         }
988     },
989 
990     /**
991      * MoveTo reverse is not implemented
992      */
993     reverse:function () {
994         return cc.MoveBy.create(this._duration, cc.p(-this._positionDelta.x, -this._positionDelta.y));
995     }
996 });
997 
998 /**
999  * @param {Number} duration duration in seconds
1000  * @param {cc.Point} deltaPosition
1001  * @return {cc.MoveBy}
1002  * @example
1003  * // example
1004  * var actionTo = cc.MoveBy.create(2, cc.p(windowSize.width - 40, windowSize.height - 40));
1005  */
1006 cc.MoveBy.create = function (duration, deltaPosition) {
1007     var moveBy = new cc.MoveBy();
1008     moveBy.initWithDuration(duration, deltaPosition);
1009     return moveBy;
1010 };
1011 
1012 
1013 /**
1014  * Moves a CCNode object to the position x,y. x and y are absolute coordinates by modifying it's position attribute. <br/>
1015  * Several CCMoveTo actions can be concurrently called, and the resulting                                            <br/>
1016  * movement will be the sum of individual movements.
1017  * @class
1018  * @extends cc.MoveBy
1019  */
1020 cc.MoveTo = cc.MoveBy.extend(/** @lends cc.MoveTo# */{
1021     _endPosition:null,
1022     ctor:function () {
1023         cc.MoveBy.prototype.ctor.call(this);
1024         this._endPosition = cc.p(0, 0);
1025     },
1026 
1027     /**
1028      * @param {Number} duration  duration in seconds
1029      * @param {cc.Point} position
1030      * @return {Boolean}
1031      */
1032     initWithDuration:function (duration, position) {
1033         if (cc.MoveBy.prototype.initWithDuration.call(this, duration, position)) {
1034             this._endPosition.x = position.x;
1035             this._endPosition.y = position.y;
1036             return true;
1037         }
1038         return false;
1039     },
1040 
1041     /**
1042      * returns a new clone of the action
1043      * @returns {cc.MoveTo}
1044      */
1045     clone:function () {
1046         var action = new cc.MoveTo();
1047         action.initWithDuration(this._duration, this._endPosition);
1048         return action;
1049     },
1050 
1051     /**
1052      * @param {cc.Node} target
1053      */
1054     startWithTarget:function (target) {
1055         cc.MoveBy.prototype.startWithTarget.call(this, target);
1056         this._positionDelta.x = this._endPosition.x - target.getPositionX();
1057         this._positionDelta.y = this._endPosition.y - target.getPositionY();
1058     }
1059 });
1060 /**
1061  * @param {Number} duration duration in seconds
1062  * @param {cc.Point} position
1063  * @return {cc.MoveBy}
1064  * @example
1065  * // example
1066  * var actionBy = cc.MoveTo.create(2, cc.p(80, 80));
1067  */
1068 cc.MoveTo.create = function (duration, position) {
1069     var moveTo = new cc.MoveTo();
1070     moveTo.initWithDuration(duration, position);
1071     return moveTo;
1072 };
1073 
1074 /**
1075  * Skews a cc.Node object to given angles by modifying it's skewX and skewY attributes
1076  * @class
1077  * @extends cc.ActionInterval
1078  */
1079 cc.SkewTo = cc.ActionInterval.extend(/** @lends cc.SkewTo# */{
1080     _skewX:0,
1081     _skewY:0,
1082     _startSkewX:0,
1083     _startSkewY:0,
1084     _endSkewX:0,
1085     _endSkewY:0,
1086     _deltaX:0,
1087     _deltaY:0,
1088 
1089     ctor:function () {
1090         cc.ActionInterval.prototype.ctor.call(this);
1091         this._skewX = 0;
1092         this._skewY = 0;
1093         this._startSkewX = 0;
1094         this._startSkewY = 0;
1095         this._endSkewX = 0;
1096         this._endSkewY = 0;
1097         this._deltaX = 0;
1098         this._deltaY = 0;
1099     },
1100 
1101     /**
1102      * @param {Number} t time in seconds
1103      * @param {Number} sx
1104      * @param {Number} sy
1105      * @return {Boolean}
1106      */
1107     initWithDuration:function (t, sx, sy) {
1108         var ret = false;
1109         if (cc.ActionInterval.prototype.initWithDuration.call(this, t)) {
1110             this._endSkewX = sx;
1111             this._endSkewY = sy;
1112             ret = true;
1113         }
1114         return ret;
1115     },
1116 
1117     /**
1118      * returns a new clone of the action
1119      * @returns {cc.SkewTo}
1120      */
1121     clone:function () {
1122         var action = new cc.SkewTo();
1123         action.initWithDuration(this._duration, this._endSkewX, this._endSkewY);
1124         return action;
1125     },
1126 
1127     /**
1128      * @param {cc.Node} target
1129      */
1130     startWithTarget:function (target) {
1131         cc.ActionInterval.prototype.startWithTarget.call(this, target);
1132 
1133         this._startSkewX = target.getSkewX() % 180;
1134         this._deltaX = this._endSkewX - this._startSkewX;
1135         if (this._deltaX > 180)
1136             this._deltaX -= 360;
1137         if (this._deltaX < -180)
1138             this._deltaX += 360;
1139 
1140         this._startSkewY = target.getSkewY() % 360;
1141         this._deltaY = this._endSkewY - this._startSkewY;
1142         if (this._deltaY > 180)
1143             this._deltaY -= 360;
1144         if (this._deltaY < -180)
1145             this._deltaY += 360;
1146     },
1147 
1148     /**
1149      * @param {Number} t time in seconds
1150      */
1151     update:function (t) {
1152         this._target.setSkewX(this._startSkewX + this._deltaX * t);
1153         this._target.setSkewY(this._startSkewY + this._deltaY * t);
1154     }
1155 });
1156 /**
1157  * @param {Number} t time in seconds
1158  * @param {Number} sx
1159  * @param {Number} sy
1160  * @return {cc.SkewTo}
1161  * @example
1162  * // example
1163  * var actionTo = cc.SkewTo.create(2, 37.2, -37.2);
1164  */
1165 cc.SkewTo.create = function (t, sx, sy) {
1166     var skewTo = new cc.SkewTo();
1167     if (skewTo)
1168         skewTo.initWithDuration(t, sx, sy);
1169     return skewTo;
1170 };
1171 
1172 /** Skews a cc.Node object by skewX and skewY degrees
1173  * @class
1174  * @extends cc.SkewTo
1175  */
1176 cc.SkewBy = cc.SkewTo.extend(/** @lends cc.SkewBy# */{
1177     /**
1178      * @param {Number} t time in seconds
1179      * @param {Number} deltaSkewX  skew in degrees for X axis
1180      * @param {Number} deltaSkewY  skew in degrees for Y axis
1181      * @return {Boolean}
1182      */
1183     initWithDuration:function (t, deltaSkewX, deltaSkewY) {
1184         var ret = false;
1185         if (cc.SkewTo.prototype.initWithDuration.call(this, t, deltaSkewX, deltaSkewY)) {
1186             this._skewX = deltaSkewX;
1187             this._skewY = deltaSkewY;
1188             ret = true;
1189         }
1190         return ret;
1191     },
1192 
1193     /**
1194      * returns a new clone of the action
1195      * @returns {cc.SkewBy}
1196      */
1197     clone:function () {
1198         var action = new cc.SkewBy();
1199         action.initWithDuration(this._duration, this._skewX, this._skewY);
1200         return action;
1201     },
1202 
1203     /**
1204      * @param {cc.Node} target
1205      */
1206     startWithTarget:function (target) {
1207         cc.SkewTo.prototype.startWithTarget.call(this, target);
1208         this._deltaX = this._skewX;
1209         this._deltaY = this._skewY;
1210         this._endSkewX = this._startSkewX + this._deltaX;
1211         this._endSkewY = this._startSkewY + this._deltaY;
1212     },
1213 
1214     /**
1215      * @return {cc.ActionInterval}
1216      */
1217     reverse:function () {
1218         return cc.SkewBy.create(this._duration, -this._skewX, -this._skewY);
1219     }
1220 });
1221 /**
1222  * @param {Number} t time in seconds
1223  * @param {Number} sx sx skew in degrees for X axis
1224  * @param {Number} sy sy skew in degrees for Y axis
1225  * @return {cc.SkewBy}
1226  * @example
1227  * // example
1228  * var actionBy = cc.SkewBy.create(2, 0, -90);
1229  */
1230 cc.SkewBy.create = function (t, sx, sy) {
1231     var skewBy = new cc.SkewBy();
1232     if (skewBy)
1233         skewBy.initWithDuration(t, sx, sy);
1234     return skewBy;
1235 };
1236 
1237 
1238 /**  Moves a cc.Node object simulating a parabolic jump movement by modifying it's position attribute.
1239  * @class
1240  * @extends cc.ActionInterval
1241  */
1242 cc.JumpBy = cc.ActionInterval.extend(/** @lends cc.JumpBy# */{
1243     _startPosition:null,
1244     _delta:null,
1245     _height:0,
1246     _jumps:0,
1247     _previousPosition:null,
1248 
1249     ctor:function () {
1250         cc.ActionInterval.prototype.ctor.call(this);
1251         this._startPosition = cc.p(0, 0);
1252         this._previousPosition = cc.p(0, 0);
1253         this._delta = cc.p(0, 0);
1254         this._height = 0;
1255         this._jumps = 0;
1256     },
1257     /**
1258      * @param {Number} duration
1259      * @param {cc.Point} position
1260      * @param {Number} height
1261      * @param {Number} jumps
1262      * @return {Boolean}
1263      */
1264     initWithDuration:function (duration, position, height, jumps) {
1265         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
1266             this._delta.x = position.x;
1267             this._delta.y = position.y;
1268             this._height = height;
1269             this._jumps = jumps;
1270             return true;
1271         }
1272         return false;
1273     },
1274 
1275     /**
1276      * returns a new clone of the action
1277      * @returns {cc.JumpBy}
1278      */
1279     clone:function () {
1280         var action = new cc.JumpBy();
1281         action.initWithDuration(this._duration, this._delta, this._height, this._jumps);
1282         return action;
1283     },
1284 
1285     /**
1286      * @param {cc.Node} target
1287      */
1288     startWithTarget:function (target) {
1289         cc.ActionInterval.prototype.startWithTarget.call(this, target);
1290         var locPosX = target.getPositionX();
1291         var locPosY = target.getPositionY();
1292         this._previousPosition.x = locPosX;
1293         this._previousPosition.y = locPosY;
1294         this._startPosition.x = locPosX;
1295         this._startPosition.y = locPosY;
1296     },
1297 
1298     /**
1299      * @param {Number} time
1300      */
1301     update:function (time) {
1302         if (this._target) {
1303             var frac = time * this._jumps % 1.0;
1304             var y = this._height * 4 * frac * (1 - frac);
1305             y += this._delta.y * time;
1306 
1307             var x = this._delta.x * time;
1308             var locStartPosition = this._startPosition;
1309             if (cc.ENABLE_STACKABLE_ACTIONS) {
1310                 var targetX = this._target.getPositionX();
1311                 var targetY = this._target.getPositionY();
1312                 var locPreviousPosition = this._previousPosition;
1313 
1314                 locStartPosition.x = locStartPosition.x + targetX - locPreviousPosition.x;
1315                 locStartPosition.y = locStartPosition.y + targetY - locPreviousPosition.y;
1316                 x = x + locStartPosition.x;
1317                 y = y + locStartPosition.y;
1318 
1319                 this._target.setPosition(x, y);
1320                 locPreviousPosition.x = x;
1321                 locPreviousPosition.y = y;
1322             } else {
1323                 this._target.setPosition(locStartPosition.x + x, locStartPosition.y + y);
1324             }
1325         }
1326     },
1327 
1328     /**
1329      * @return {cc.ActionInterval}
1330      */
1331     reverse:function () {
1332         return cc.JumpBy.create(this._duration, cc.p(-this._delta.x, -this._delta.y), this._height, this._jumps);
1333     }
1334 });
1335 
1336 /**
1337  * @param {Number} duration
1338  * @param {cc.Point} position
1339  * @param {Number} height
1340  * @param {Number} jumps
1341  * @return {cc.JumpBy}
1342  * @example
1343  * // example
1344  * var actionBy = cc.JumpBy.create(2, cc.p(300, 0), 50, 4);
1345  */
1346 cc.JumpBy.create = function (duration, position, height, jumps) {
1347     var jumpBy = new cc.JumpBy();
1348     jumpBy.initWithDuration(duration, position, height, jumps);
1349     return jumpBy;
1350 };
1351 
1352 /**  Moves a cc.Node object to a parabolic position simulating a jump movement by modifying it's position attribute.
1353  * @class
1354  * @extends cc.JumpBy
1355  */
1356 cc.JumpTo = cc.JumpBy.extend(/** @lends cc.JumpTo# */{
1357     /**
1358      * @param {cc.Node} target
1359      */
1360     startWithTarget:function (target) {
1361         cc.JumpBy.prototype.startWithTarget.call(this, target);
1362         this._delta.x = this._delta.x - this._startPosition.x;
1363         this._delta.y = this._delta.y - this._startPosition.y;
1364     },
1365 
1366     /**
1367      * returns a new clone of the action
1368      * @returns {cc.JumpTo}
1369      */
1370     clone:function () {
1371         var action = new cc.JumpTo();
1372         action.initWithDuration(this._duration, this._delta, this._height, this._jumps);
1373         return action;
1374     }
1375 });
1376 
1377 /**
1378  * @param {Number} duration
1379  * @param {cc.Point} position
1380  * @param {Number} height
1381  * @param {Number} jumps
1382  * @return {cc.JumpTo}
1383  * @example
1384  * // example
1385  * var actionTo = cc.JumpTo.create(2, cc.p(300, 300), 50, 4);
1386  */
1387 cc.JumpTo.create = function (duration, position, height, jumps) {
1388     var jumpTo = new cc.JumpTo();
1389     jumpTo.initWithDuration(duration, position, height, jumps);
1390     return jumpTo;
1391 };
1392 
1393 /**
1394  * @function
1395  * @param {Number} a
1396  * @param {Number} b
1397  * @param {Number} c
1398  * @param {Number} d
1399  * @param {Number} t
1400  * @return {Number}
1401  */
1402 cc.bezierAt = function (a, b, c, d, t) {
1403     return (Math.pow(1 - t, 3) * a +
1404         3 * t * (Math.pow(1 - t, 2)) * b +
1405         3 * Math.pow(t, 2) * (1 - t) * c +
1406         Math.pow(t, 3) * d );
1407 };
1408 
1409 /** An action that moves the target with a cubic Bezier curve by a certain distance.
1410  * @class
1411  * @extends cc.ActionInterval
1412  */
1413 cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{
1414     _config:null,
1415     _startPosition:null,
1416     _previousPosition:null,
1417 
1418     /**
1419      * Constructor
1420      */
1421     ctor:function () {
1422         cc.ActionInterval.prototype.ctor.call(this);
1423         this._config = [];
1424         this._startPosition = cc.p(0, 0);
1425         this._previousPosition = cc.p(0, 0);
1426     },
1427     /**
1428      * @param {Number} t time in seconds
1429      * @param {Array} c Array of points
1430      * @return {Boolean}
1431      */
1432     initWithDuration:function (t, c) {
1433         if (cc.ActionInterval.prototype.initWithDuration.call(this, t)) {
1434             this._config = c;
1435             return true;
1436         }
1437         return false;
1438     },
1439 
1440     /**
1441      * returns a new clone of the action
1442      * @returns {cc.BezierBy}
1443      */
1444     clone:function () {
1445         var action = new cc.BezierBy();
1446         var newConfigs = [];
1447         for (var i = 0; i < this._config.length; i++) {
1448             var selConf = this._config[i];
1449             newConfigs.push(cc.p(selConf.x, selConf.y));
1450         }
1451         action.initWithDuration(this._duration, newConfigs);
1452         return action;
1453     },
1454 
1455     /**
1456      * @param {cc.Node} target
1457      */
1458     startWithTarget:function (target) {
1459         cc.ActionInterval.prototype.startWithTarget.call(this, target);
1460         var locPosX = target.getPositionX();
1461         var locPosY = target.getPositionY();
1462         this._previousPosition.x = locPosX;
1463         this._previousPosition.y = locPosY;
1464         this._startPosition.x = locPosX;
1465         this._startPosition.y = locPosY;
1466     },
1467 
1468     /**
1469      * @param {Number} time
1470      */
1471     update:function (time) {
1472         if (this._target) {
1473             var locConfig = this._config;
1474             var xa = 0;
1475             var xb = locConfig[0].x;
1476             var xc = locConfig[1].x;
1477             var xd = locConfig[2].x;
1478 
1479             var ya = 0;
1480             var yb = locConfig[0].y;
1481             var yc = locConfig[1].y;
1482             var yd = locConfig[2].y;
1483 
1484             var x = cc.bezierAt(xa, xb, xc, xd, time);
1485             var y = cc.bezierAt(ya, yb, yc, yd, time);
1486 
1487             var locStartPosition = this._startPosition;
1488             if (cc.ENABLE_STACKABLE_ACTIONS) {
1489                 var targetX = this._target.getPositionX();
1490                 var targetY = this._target.getPositionY();
1491                 var locPreviousPosition = this._previousPosition;
1492 
1493                 locStartPosition.x = locStartPosition.x + targetX - locPreviousPosition.x;
1494                 locStartPosition.y = locStartPosition.y + targetY - locPreviousPosition.y;
1495                 x = x + locStartPosition.x;
1496                 y = y + locStartPosition.y;
1497                 this._target.setPosition(x, y);
1498                 locPreviousPosition.x = x;
1499                 locPreviousPosition.y = y;
1500             } else {
1501                 this._target.setPosition(locStartPosition.x + x, locStartPosition.y + y);
1502             }
1503         }
1504     },
1505 
1506     /**
1507      * @return {cc.ActionInterval}
1508      */
1509     reverse:function () {
1510         var locConfig = this._config;
1511         var r = [
1512             cc.pAdd(locConfig[1], cc.pNeg(locConfig[2])),
1513             cc.pAdd(locConfig[0], cc.pNeg(locConfig[2])),
1514             cc.pNeg(locConfig[2]) ];
1515         return cc.BezierBy.create(this._duration, r);
1516     }
1517 });
1518 
1519 /**
1520  * @param {Number} t time in seconds
1521  * @param {Array} c Array of points
1522  * @return {cc.BezierBy}
1523  * @example
1524  * // example
1525  * var bezier = [cc.p(0, windowSize.height / 2), cc.p(300, -windowSize.height / 2), cc.p(300, 100)];
1526  * var bezierForward = cc.BezierBy.create(3, bezier);
1527  *
1528  */
1529 cc.BezierBy.create = function (t, c) {
1530     var bezierBy = new cc.BezierBy();
1531     bezierBy.initWithDuration(t, c);
1532     return bezierBy;
1533 };
1534 
1535 
1536 /** An action that moves the target with a cubic Bezier curve to a destination point.
1537  * @class
1538  * @extends cc.BezierBy
1539  */
1540 cc.BezierTo = cc.BezierBy.extend(/** @lends cc.BezierTo# */{
1541     _toConfig:null,
1542 
1543     ctor:function () {
1544         cc.BezierBy.prototype.ctor.call(this);
1545         this._toConfig = [];
1546     },
1547 
1548     /**
1549      * @param {Number} t time in seconds
1550      * @param {Array} c Array of points
1551      * @return {Boolean}
1552      */
1553     initWithDuration:function (t, c) {
1554         if (cc.ActionInterval.prototype.initWithDuration.call(this, t)) {
1555             this._toConfig = c;
1556             return true;
1557         }
1558         return false;
1559     },
1560 
1561     /**
1562      * returns a new clone of the action
1563      * @returns {cc.BezierTo}
1564      */
1565     clone:function () {
1566         var action = new cc.BezierTo();
1567         action.initWithDuration(this._duration, this._toConfig);
1568         return action;
1569     },
1570 
1571     /**
1572      * @param {cc.Node} target
1573      */
1574     startWithTarget:function (target) {
1575         cc.BezierBy.prototype.startWithTarget.call(this, target);
1576         var locStartPos = this._startPosition;
1577         var locToConfig = this._toConfig;
1578         var locConfig = this._config;
1579 
1580         locConfig[0] = cc.pSub(locToConfig[0], locStartPos);
1581         locConfig[1] = cc.pSub(locToConfig[1], locStartPos);
1582         locConfig[2] = cc.pSub(locToConfig[2], locStartPos);
1583     }
1584 });
1585 /**
1586  * @param {Number} t
1587  * @param {Array} c array of points
1588  * @return {cc.BezierTo}
1589  * @example
1590  * // example
1591  * var bezier = [cc.p(0, windowSize.height / 2), cc.p(300, -windowSize.height / 2), cc.p(300, 100)];
1592  * var bezierTo = cc.BezierTo.create(2, bezier);
1593  */
1594 cc.BezierTo.create = function (t, c) {
1595     var bezierTo = new cc.BezierTo();
1596     bezierTo.initWithDuration(t, c);
1597     return bezierTo;
1598 };
1599 
1600 
1601 /** Scales a cc.Node object to a zoom factor by modifying it's scale attribute.
1602  * @warning This action doesn't support "reverse"
1603  * @class
1604  * @extends cc.ActionInterval
1605  */
1606 cc.ScaleTo = cc.ActionInterval.extend(/** @lends cc.ScaleTo# */{
1607     _scaleX:1,
1608     _scaleY:1,
1609     _startScaleX:1,
1610     _startScaleY:1,
1611     _endScaleX:0,
1612     _endScaleY:0,
1613     _deltaX:0,
1614     _deltaY:0,
1615 
1616     ctor:function () {
1617         cc.ActionInterval.prototype.ctor.call(this);
1618         this._scaleX = 1;
1619         this._scaleY = 1;
1620         this._startScaleX = 1;
1621         this._startScaleY = 1;
1622         this._endScaleX = 0;
1623         this._endScaleY = 0;
1624         this._deltaX = 0;
1625         this._deltaY = 0;
1626     },
1627 
1628     /**
1629      * @param {Number} duration
1630      * @param {Number} sx
1631      * @param {Number} [sy=]
1632      * @return {Boolean}
1633      */
1634     initWithDuration:function (duration, sx, sy) { //function overload here
1635         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
1636             this._endScaleX = sx;
1637             this._endScaleY = (sy != null) ? sy : sx;
1638             return true;
1639         }
1640         return false;
1641     },
1642 
1643     /**
1644      * returns a new clone of the action
1645      * @returns {cc.ScaleTo}
1646      */
1647     clone:function () {
1648         var action = new cc.ScaleTo();
1649         action.initWithDuration(this._duration, this._endScaleX, this._endScaleY);
1650         return action;
1651     },
1652 
1653     /**
1654      * @param {cc.Node} target
1655      */
1656     startWithTarget:function (target) {
1657         cc.ActionInterval.prototype.startWithTarget.call(this, target);
1658         this._startScaleX = target.getScaleX();
1659         this._startScaleY = target.getScaleY();
1660         this._deltaX = this._endScaleX - this._startScaleX;
1661         this._deltaY = this._endScaleY - this._startScaleY;
1662     },
1663 
1664     /**
1665      * @param {Number} time
1666      */
1667     update:function (time) {
1668         if (this._target)
1669             this._target.setScale(this._startScaleX + this._deltaX * time, this._startScaleY + this._deltaY * time);
1670     }
1671 });
1672 /**
1673  * @param {Number} duration
1674  * @param {Number} sx  scale parameter in X
1675  * @param {Number} [sy=] scale parameter in Y, if Null equal to sx
1676  * @return {cc.ScaleTo}
1677  * @example
1678  * // example
1679  * // It scales to 0.5 in both X and Y.
1680  * var actionTo = cc.ScaleTo.create(2, 0.5);
1681  *
1682  * // It scales to 0.5 in x and 2 in Y
1683  * var actionTo = cc.ScaleTo.create(2, 0.5, 2);
1684  */
1685 cc.ScaleTo.create = function (duration, sx, sy) { //function overload
1686     var scaleTo = new cc.ScaleTo();
1687     scaleTo.initWithDuration(duration, sx, sy);
1688     return scaleTo;
1689 };
1690 
1691 
1692 /** Scales a cc.Node object a zoom factor by modifying it's scale attribute.
1693  * @class
1694  * @extends cc.ScaleTo
1695  */
1696 cc.ScaleBy = cc.ScaleTo.extend(/** @lends cc.ScaleBy# */{
1697     /**
1698      * @param {Number} target
1699      */
1700     startWithTarget:function (target) {
1701         cc.ScaleTo.prototype.startWithTarget.call(this, target);
1702         this._deltaX = this._startScaleX * this._endScaleX - this._startScaleX;
1703         this._deltaY = this._startScaleY * this._endScaleY - this._startScaleY;
1704     },
1705 
1706     /**
1707      * @return {cc.ActionInterval}
1708      */
1709     reverse:function () {
1710         return cc.ScaleBy.create(this._duration, 1 / this._endScaleX, 1 / this._endScaleY);
1711     },
1712 
1713     /**
1714      * returns a new clone of the action
1715      * @returns {cc.ScaleBy}
1716      */
1717     clone:function () {
1718         var action = new cc.ScaleBy();
1719         action.initWithDuration(this._duration, this._endScaleX, this._endScaleY);
1720         return action;
1721     }
1722 });
1723 /**
1724  * @param {Number} duration duration in seconds
1725  * @param {Number} sx sx  scale parameter in X
1726  * @param {Number|Null} [sy=] sy scale parameter in Y, if Null equal to sx
1727  * @return {cc.ScaleBy}
1728  * @example
1729  * // example without sy, it scales by 2 both in X and Y
1730  * var actionBy = cc.ScaleBy.create(2, 2);
1731  *
1732  * //example with sy, it scales by 0.25 in X and 4.5 in Y
1733  * var actionBy2 = cc.ScaleBy.create(2, 0.25, 4.5);
1734  */
1735 cc.ScaleBy.create = function (duration, sx, sy) {
1736     var scaleBy = new cc.ScaleBy();
1737     scaleBy.initWithDuration(duration, sx, sy);
1738     return scaleBy;
1739 };
1740 
1741 /** Blinks a cc.Node object by modifying it's visible attribute
1742  * @class
1743  * @extends cc.ActionInterval
1744  */
1745 cc.Blink = cc.ActionInterval.extend(/** @lends cc.Blink# */{
1746     _times:0,
1747     _originalState:false,
1748 
1749     ctor:function () {
1750         cc.ActionInterval.prototype.ctor.call(this);
1751         this._times = 0;
1752         this._originalState = false;
1753     },
1754 
1755     /**
1756      * @param {Number} duration duration in seconds
1757      * @param {Number} blinks blinks in times
1758      * @return {Boolean}
1759      */
1760     initWithDuration:function (duration, blinks) {
1761         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
1762             this._times = blinks;
1763             return true;
1764         }
1765         return false;
1766     },
1767 
1768     /**
1769      * returns a new clone of the action
1770      * @returns {cc.Blink}
1771      */
1772     clone:function () {
1773         var action = new cc.Blink();
1774         action.initWithDuration(this._duration, this._times);
1775         return action;
1776     },
1777 
1778     /**
1779      * @param {Number} time time in seconds
1780      */
1781     update:function (time) {
1782         if (this._target && !this.isDone()) {
1783             var slice = 1.0 / this._times;
1784             var m = time % slice;
1785             this._target.setVisible(m > (slice / 2));
1786         }
1787     },
1788 
1789     startWithTarget:function (target) {
1790         cc.ActionInterval.prototype.startWithTarget.call(this, target);
1791         this._originalState = target.isVisible();
1792     },
1793 
1794     stop:function () {
1795         this._target.setVisible(this._originalState);
1796         cc.ActionInterval.prototype.stop.call(this);
1797     },
1798 
1799     /**
1800      * @return {cc.ActionInterval}
1801      */
1802     reverse:function () {
1803         return cc.Blink.create(this._duration, this._times);
1804     }
1805 });
1806 /**
1807  * @param {Number} duration  duration in seconds
1808  * @param blinks blinks in times
1809  * @return {cc.Blink}
1810  * @example
1811  * // example
1812  * var action = cc.Blink.create(2, 10);
1813  */
1814 cc.Blink.create = function (duration, blinks) {
1815     var blink = new cc.Blink();
1816     blink.initWithDuration(duration, blinks);
1817     return blink;
1818 };
1819 
1820 /** Fades an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from the current value to a custom one.
1821  * @warning This action doesn't support "reverse"
1822  * @class
1823  * @extends cc.ActionInterval
1824  */
1825 cc.FadeTo = cc.ActionInterval.extend(/** @lends cc.FadeTo# */{
1826     _toOpacity:null,
1827     _fromOpacity:null,
1828 
1829     ctor:function () {
1830         cc.ActionInterval.prototype.ctor.call(this);
1831         this._toOpacity = 0;
1832         this._fromOpacity = 0;
1833     },
1834 
1835     /**
1836      * @param {Number} duration  duration in seconds
1837      * @param {Number} opacity
1838      * @return {Boolean}
1839      */
1840     initWithDuration:function (duration, opacity) {
1841         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
1842             this._toOpacity = opacity;
1843             return true;
1844         }
1845         return false;
1846     },
1847 
1848     /**
1849      * returns a new clone of the action
1850      * @returns {cc.FadeTo}
1851      */
1852     clone:function () {
1853         var action = new cc.FadeTo();
1854         action.initWithDuration(this._duration, this._toOpacity);
1855         return action;
1856     },
1857 
1858     /**
1859      * @param {Number} time time in seconds
1860      */
1861     update:function (time) {
1862         if (this._target.RGBAProtocol) {
1863             var fromOpacity = this._fromOpacity;
1864             this._target.setOpacity((fromOpacity + (this._toOpacity - fromOpacity) * time));
1865         }
1866     },
1867 
1868     /**
1869      * @param {cc.Sprite} target
1870      */
1871     startWithTarget:function (target) {
1872         cc.ActionInterval.prototype.startWithTarget.call(this, target);
1873         if(this._target.RGBAProtocol){
1874             this._fromOpacity = target.getOpacity();
1875         }
1876     }
1877 });
1878 
1879 /**
1880  * @param {Number} duration
1881  * @param {Number} opacity 0-255, 0 is transparent
1882  * @return {cc.FadeTo}
1883  * @example
1884  * // example
1885  * var action = cc.FadeTo.create(1.0, 0);
1886  */
1887 cc.FadeTo.create = function (duration, opacity) {
1888     var fadeTo = new cc.FadeTo();
1889     fadeTo.initWithDuration(duration, opacity);
1890     return fadeTo;
1891 };
1892 
1893 /** Fades In an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 0 to 255.<br/>
1894  * The "reverse" of this action is FadeOut
1895  * @class
1896  * @extends cc.FadeTo
1897  */
1898 cc.FadeIn = cc.FadeTo.extend(/** @lends cc.FadeIn# */{
1899     _reverseAction: null,
1900     /**
1901      * @return {cc.ActionInterval}
1902      */
1903     reverse:function () {
1904         var action = new cc.FadeOut();
1905         action.initWithDuration(this._duration, 0);
1906         return action;
1907     },
1908 
1909     /**
1910      * returns a new clone of the action
1911      * @returns {cc.FadeIn}
1912      */
1913     clone:function () {
1914         var action = new cc.FadeIn();
1915         action.initWithDuration(this._duration, this._toOpacity);
1916         return action;
1917     },
1918 
1919     /**
1920      * @param {cc.Sprite} target
1921      */
1922     startWithTarget:function (target) {
1923         if(this._reverseAction)
1924             this._toOpacity = this._reverseAction._fromOpacity;
1925         cc.FadeTo.prototype.startWithTarget.call(this, target);
1926     }
1927 });
1928 
1929 /**
1930  * @param {Number} duration duration in seconds
1931  * @param {Number} [toOpacity] to opacity
1932  * @return {cc.FadeIn}
1933  * @example
1934  * //example
1935  * var action = cc.FadeIn.create(1.0);
1936  */
1937 cc.FadeIn.create = function (duration, toOpacity) {
1938     if(toOpacity == null)
1939         toOpacity = 255;
1940     var action = new cc.FadeIn();
1941     action.initWithDuration(duration, toOpacity);
1942     return action;
1943 };
1944 
1945 
1946 /** Fades Out an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 255 to 0.
1947  * The "reverse" of this action is FadeIn
1948  * @class
1949  * @extends cc.FadeTo
1950  */
1951 cc.FadeOut = cc.FadeTo.extend(/** @lends cc.FadeOut# */{
1952     /**
1953      * @return {cc.ActionInterval}
1954      */
1955     reverse:function () {
1956         var action = new cc.FadeIn();
1957         action._reverseAction = this;
1958         action.initWithDuration(this._duration, 255);
1959         return action;
1960     },
1961 
1962     /**
1963      * returns a new clone of the action
1964      * @returns {cc.FadeOut}
1965      */
1966     clone:function () {
1967         var action = new cc.FadeOut();
1968         action.initWithDuration(this._duration, this._toOpacity);
1969         return action;
1970     }
1971 });
1972 
1973 /**
1974  * @param {Number} d  duration in seconds
1975  * @return {cc.FadeOut}
1976  * @example
1977  * // example
1978  * var action = cc.FadeOut.create(1.0);
1979  */
1980 cc.FadeOut.create = function (d) {
1981     var action = new cc.FadeOut();
1982     action.initWithDuration(d, 0);
1983     return action;
1984 };
1985 
1986 /** Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one.
1987  * @warning This action doesn't support "reverse"
1988  * @class
1989  * @extends cc.ActionInterval
1990  */
1991 cc.TintTo = cc.ActionInterval.extend(/** @lends cc.TintTo# */{
1992     _to:null,
1993     _from:null,
1994 
1995     ctor:function () {
1996         cc.ActionInterval.prototype.ctor.call(this);
1997         this._to = cc.c3b(0, 0, 0);
1998         this._from = cc.c3b(0, 0, 0);
1999     },
2000 
2001     /**
2002      * @param {Number} duration
2003      * @param {Number} red 0-255
2004      * @param {Number} green 0-255
2005      * @param {Number} blue 0-255
2006      * @return {Boolean}
2007      */
2008     initWithDuration:function (duration, red, green, blue) {
2009         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
2010             this._to = cc.c3b(red, green, blue);
2011             return true;
2012         }
2013         return false;
2014     },
2015 
2016     /**
2017      * returns a new clone of the action
2018      * @returns {cc.TintTo}
2019      */
2020     clone:function () {
2021         var action = new cc.TintTo();
2022         var locTo = this._to;
2023         action.initWithDuration(this._duration, locTo.r, locTo.g, locTo.b);
2024         return action;
2025     },
2026 
2027     /**
2028      * @param {cc.Sprite} target
2029      */
2030     startWithTarget:function (target) {
2031         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2032         if (this._target.RGBAProtocol) {
2033             this._from = this._target.getColor();
2034         }
2035     },
2036 
2037     /**
2038      * @param {Number} time time in seconds
2039      */
2040     update:function (time) {
2041         var locFrom = this._from, locTo = this._to;
2042         if (this._target.RGBAProtocol) {
2043             this._target.setColor(cc.c3b(locFrom.r + (locTo.r - locFrom.r) * time,
2044                 (locFrom.g + (locTo.g - locFrom.g) * time), (locFrom.b + (locTo.b - locFrom.b) * time)));
2045         }
2046     }
2047 });
2048 
2049 /**
2050  * @param {Number} duration
2051  * @param {Number} red 0-255
2052  * @param {Number} green  0-255
2053  * @param {Number} blue 0-255
2054  * @return {cc.TintTo}
2055  * @example
2056  * // example
2057  * var action = cc.TintTo.create(2, 255, 0, 255);
2058  */
2059 cc.TintTo.create = function (duration, red, green, blue) {
2060     var tintTo = new cc.TintTo();
2061     tintTo.initWithDuration(duration, red, green, blue);
2062     return tintTo;
2063 };
2064 
2065 
2066 /**  Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one.
2067  * @class
2068  * @extends cc.ActionInterval
2069  */
2070 cc.TintBy = cc.ActionInterval.extend(/** @lends cc.TintBy# */{
2071     _deltaR:0,
2072     _deltaG:0,
2073     _deltaB:0,
2074 
2075     _fromR:0,
2076     _fromG:0,
2077     _fromB:0,
2078 
2079     ctor:function () {
2080         cc.ActionInterval.prototype.ctor.call(this);
2081         this._deltaR = 0;
2082         this._deltaG = 0;
2083         this._deltaB = 0;
2084         this._fromR = 0;
2085         this._fromG = 0;
2086         this._fromB = 0;
2087     },
2088 
2089     /**
2090      * @param {Number} duration
2091      * @param {Number} deltaRed 0-255
2092      * @param {Number} deltaGreen 0-255
2093      * @param {Number} deltaBlue 0-255
2094      * @return {Boolean}
2095      */
2096     initWithDuration:function (duration, deltaRed, deltaGreen, deltaBlue) {
2097         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
2098             this._deltaR = deltaRed;
2099             this._deltaG = deltaGreen;
2100             this._deltaB = deltaBlue;
2101             return true;
2102         }
2103         return false;
2104     },
2105 
2106     /**
2107      * returns a new clone of the action
2108      * @returns {cc.TintBy}
2109      */
2110     clone:function () {
2111         var action = new cc.TintBy();
2112         action.initWithDuration(this._duration, this._deltaR, this._deltaG, this._deltaB);
2113         return action;
2114     },
2115 
2116     /**
2117      * @param {cc.Sprite} target
2118      */
2119     startWithTarget:function (target) {
2120         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2121         if (target.RGBAProtocol) {
2122             var color = target.getColor();
2123             this._fromR = color.r;
2124             this._fromG = color.g;
2125             this._fromB = color.b;
2126         }
2127     },
2128 
2129     /**
2130      * @param {Number} time time in seconds
2131      */
2132     update:function (time) {
2133         if (this._target.RGBAProtocol) {
2134             this._target.setColor(cc.c3b((this._fromR + this._deltaR * time),
2135                 (this._fromG + this._deltaG * time),
2136                 (this._fromB + this._deltaB * time)));
2137         }
2138     },
2139 
2140     /**
2141      * @return {cc.ActionInterval}
2142      */
2143     reverse:function () {
2144         return cc.TintBy.create(this._duration, -this._deltaR, -this._deltaG, -this._deltaB);
2145     }
2146 });
2147 
2148 /**
2149  * @param {Number} duration  duration in seconds
2150  * @param {Number} deltaRed
2151  * @param {Number} deltaGreen
2152  * @param {Number} deltaBlue
2153  * @return {cc.TintBy}
2154  * @example
2155  * // example
2156  * var action = cc.TintBy.create(2, -127, -255, -127);
2157  */
2158 cc.TintBy.create = function (duration, deltaRed, deltaGreen, deltaBlue) {
2159     var tintBy = new cc.TintBy();
2160     tintBy.initWithDuration(duration, deltaRed, deltaGreen, deltaBlue);
2161     return tintBy;
2162 };
2163 
2164 /** Delays the action a certain amount of seconds
2165  * @class
2166  * @extends cc.ActionInterval
2167  */
2168 cc.DelayTime = cc.ActionInterval.extend(/** @lends cc.DelayTime# */{
2169     /**
2170      * @param {Number} time time in seconds
2171      */
2172     update:function (time) {
2173     },
2174 
2175     /**
2176      * @return {cc.ActionInterval}
2177      */
2178     reverse:function () {
2179         return cc.DelayTime.create(this._duration);
2180     },
2181 
2182     /**
2183      * returns a new clone of the action
2184      * @returns {cc.DelayTime}
2185      */
2186     clone:function () {
2187         var action = new cc.DelayTime();
2188         action.initWithDuration(this._duration);
2189         return action;
2190     }
2191 });
2192 
2193 /**
2194  * @param {Number} d duration in seconds
2195  * @return {cc.DelayTime}
2196  * @example
2197  * // example
2198  * var delay = cc.DelayTime.create(1);
2199  */
2200 cc.DelayTime.create = function (d) {
2201     var action = new cc.DelayTime();
2202     action.initWithDuration(d);
2203     return action;
2204 };
2205 
2206 /**
2207  * Executes an action in reverse order, from time=duration to time=0
2208  * @warning Use this action carefully. This action is not
2209  * sequenceable. Use it as the default "reversed" method
2210  * of your own actions, but using it outside the "reversed"
2211  * scope is not recommended.
2212  * @class
2213  * @extends cc.ActionInterval
2214  */
2215 cc.ReverseTime = cc.ActionInterval.extend(/** @lends cc.ReverseTime# */{
2216     _other:null,
2217 
2218     ctor:function () {
2219         cc.ActionInterval.prototype.ctor.call(this);
2220         this._other = null;
2221     },
2222 
2223     /**
2224      * @param {cc.FiniteTimeAction} action
2225      * @return {Boolean}
2226      */
2227     initWithAction:function (action) {
2228         if(!action)
2229             throw "cc.ReverseTime.initWithAction(): action must be non null";
2230         if(action == this._other)
2231             throw "cc.ReverseTime.initWithAction(): the action was already passed in.";
2232 
2233         if (cc.ActionInterval.prototype.initWithDuration.call(this, action.getDuration())) {
2234             // Don't leak if action is reused
2235             this._other = action;
2236             return true;
2237         }
2238         return false;
2239     },
2240 
2241     /**
2242      * returns a new clone of the action
2243      * @returns {cc.ReverseTime}
2244      */
2245     clone:function () {
2246         var action = new cc.ReverseTime();
2247         action.initWithAction(this._other.clone());
2248         return action;
2249     },
2250 
2251     /**
2252      * @param {cc.Node} target
2253      */
2254     startWithTarget:function (target) {
2255         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2256         this._other.startWithTarget(target);
2257     },
2258 
2259     /**
2260      * @param {Number} time time in seconds
2261      */
2262     update:function (time) {
2263         if (this._other)
2264             this._other.update(1 - time);
2265     },
2266 
2267     /**
2268      * @return {cc.ActionInterval}
2269      */
2270     reverse:function () {
2271         return this._other.clone();
2272     },
2273 
2274     /**
2275      * Stop the action
2276      */
2277     stop:function () {
2278         this._other.stop();
2279         cc.Action.prototype.stop.call(this);
2280     }
2281 });
2282 
2283 /**
2284  * @param {cc.FiniteTimeAction} action
2285  * @return {cc.ReverseTime}
2286  * @example
2287  * // example
2288  *  var reverse = cc.ReverseTime.create(this);
2289  */
2290 cc.ReverseTime.create = function (action) {
2291     var reverseTime = new cc.ReverseTime();
2292     reverseTime.initWithAction(action);
2293     return reverseTime;
2294 };
2295 
2296 
2297 /**  Animates a sprite given the name of an Animation
2298  * @class
2299  * @extends cc.ActionInterval
2300  */
2301 cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{
2302     _animation:null,
2303     _nextFrame:0,
2304     _origFrame:null,
2305     _executedLoops:0,
2306     _splitTimes:null,
2307 
2308     ctor:function () {
2309         cc.ActionInterval.prototype.ctor.call(this);
2310         this._animation = null;
2311         this._nextFrame = 0;
2312         this._origFrame = null;
2313         this._executedLoops = 0;
2314         this._splitTimes = [];
2315     },
2316 
2317     /**
2318      * @return {cc.Animation}
2319      */
2320     getAnimation:function () {
2321         return this._animation;
2322     },
2323 
2324     /**
2325      * @param {cc.Animation} animation
2326      */
2327     setAnimation:function (animation) {
2328         this._animation = animation;
2329     },
2330 
2331     /**
2332      * @param {cc.Animation} animation
2333      * @return {Boolean}
2334      */
2335     initWithAnimation:function (animation) {
2336         if(!animation)
2337             throw "cc.Animate.initWithAnimation(): animation must be non-NULL";
2338         var singleDuration = animation.getDuration();
2339         if (this.initWithDuration(singleDuration * animation.getLoops())) {
2340             this._nextFrame = 0;
2341             this.setAnimation(animation);
2342 
2343             this._origFrame = null;
2344             this._executedLoops = 0;
2345             var locTimes = this._splitTimes;
2346             locTimes.length = 0;
2347 
2348             var accumUnitsOfTime = 0;
2349             var newUnitOfTimeValue = singleDuration / animation.getTotalDelayUnits();
2350 
2351             var frames = animation.getFrames();
2352             cc.ArrayVerifyType(frames, cc.AnimationFrame);
2353 
2354             for (var i = 0; i < frames.length; i++) {
2355                 var frame = frames[i];
2356                 var value = (accumUnitsOfTime * newUnitOfTimeValue) / singleDuration;
2357                 accumUnitsOfTime += frame.getDelayUnits();
2358                 locTimes.push(value);
2359             }
2360             return true;
2361         }
2362         return false;
2363     },
2364 
2365     /**
2366      * returns a new clone of the action
2367      * @returns {cc.Animate}
2368      */
2369     clone:function () {
2370         var action = new cc.Animate();
2371         action.initWithAnimation(this._animation.clone());
2372         return action;
2373     },
2374 
2375     /**
2376      * @param {cc.Sprite} target
2377      */
2378     startWithTarget:function (target) {
2379         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2380         if (this._animation.getRestoreOriginalFrame())
2381             this._origFrame = target.displayFrame();
2382         this._nextFrame = 0;
2383         this._executedLoops = 0;
2384     },
2385 
2386     /**
2387      * @param {Number} time
2388      */
2389     update:function (time) {
2390         // if t==1, ignore. Animation should finish with t==1
2391         if (time < 1.0) {
2392             time *= this._animation.getLoops();
2393 
2394             // new loop?  If so, reset frame counter
2395             var loopNumber = 0 | time;
2396             if (loopNumber > this._executedLoops) {
2397                 this._nextFrame = 0;
2398                 this._executedLoops++;
2399             }
2400 
2401             // new t for animations
2402             time = time % 1.0;
2403         }
2404 
2405         var frames = this._animation.getFrames();
2406         var numberOfFrames = frames.length, locSplitTimes = this._splitTimes;
2407         for (var i = this._nextFrame; i < numberOfFrames; i++) {
2408             if (locSplitTimes[i] <= time) {
2409                 this._target.setDisplayFrame(frames[i].getSpriteFrame());
2410                 this._nextFrame = i + 1;
2411             } else {
2412                 // Issue 1438. Could be more than one frame per tick, due to low frame rate or frame delta < 1/FPS
2413                 break;
2414             }
2415         }
2416     },
2417 
2418     /**
2419      * @return {cc.ActionInterval}
2420      */
2421     reverse:function () {
2422         var locAnimation = this._animation;
2423         var oldArray = locAnimation.getFrames();
2424         var newArray = [];
2425         cc.ArrayVerifyType(oldArray, cc.AnimationFrame);
2426         if (oldArray.length > 0) {
2427             for (var i = oldArray.length - 1; i >= 0; i--) {
2428                 var element = oldArray[i];
2429                 if (!element)
2430                     break;
2431                 newArray.push(element.clone());
2432             }
2433         }
2434         var newAnim = cc.Animation.createWithAnimationFrames(newArray, locAnimation.getDelayPerUnit(), locAnimation.getLoops());
2435         newAnim.setRestoreOriginalFrame(locAnimation.getRestoreOriginalFrame());
2436         return cc.Animate.create(newAnim);
2437     },
2438 
2439     /**
2440      * stop the action
2441      */
2442     stop:function () {
2443         if (this._animation.getRestoreOriginalFrame() && this._target)
2444             this._target.setDisplayFrame(this._origFrame);
2445         cc.Action.prototype.stop.call(this);
2446     }
2447 });
2448 
2449 /**
2450  * create the animate with animation
2451  * @param {cc.Animation} animation
2452  * @return {cc.Animate}
2453  * @example
2454  * // example
2455  * // create the animation with animation
2456  * var anim = cc.Animate.create(dance_grey);
2457  */
2458 cc.Animate.create = function (animation) {
2459     var animate = new cc.Animate();
2460     animate.initWithAnimation(animation);
2461     return animate;
2462 };
2463 
2464 /**
2465  * <p>
2466  *     Overrides the target of an action so that it always runs on the target<br/>
2467  *     specified at action creation rather than the one specified by runAction.
2468  * </p>
2469  * @class
2470  * @extends cc.ActionInterval
2471  */
2472 cc.TargetedAction = cc.ActionInterval.extend(/** @lends cc.TargetedAction# */{
2473     _action:null,
2474     _forcedTarget:null,
2475 
2476     ctor:function () {
2477         cc.ActionInterval.prototype.ctor.call(this);
2478         this._action = null;
2479         this._forcedTarget = null;
2480     },
2481 
2482     /**
2483      * Init an action with the specified action and forced target
2484      * @param {cc.Node} target
2485      * @param {cc.FiniteTimeAction} action
2486      * @return {Boolean}
2487      */
2488     initWithTarget:function (target, action) {
2489         if (this.initWithDuration(action.getDuration())) {
2490             this._forcedTarget = target;
2491             this._action = action;
2492             return true;
2493         }
2494         return false;
2495     },
2496 
2497     /**
2498      * returns a new clone of the action
2499      * @returns {cc.TargetedAction}
2500      */
2501     clone:function () {
2502         var action = new cc.TargetedAction();
2503         action.initWithTarget(this._forcedTarget, this._action.clone());
2504         return action;
2505     },
2506 
2507     startWithTarget:function (target) {
2508         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2509         this._action.startWithTarget(this._forcedTarget);
2510     },
2511 
2512     stop:function () {
2513         this._action.stop();
2514     },
2515 
2516     update:function (time) {
2517         this._action.update(time);
2518     },
2519 
2520     /**
2521      * return the target that the action will be forced to run with
2522      * @return {cc.Node}
2523      */
2524     getForcedTarget:function () {
2525         return this._forcedTarget;
2526     },
2527 
2528     /**
2529      * set the target that the action will be forced to run with
2530      * @param {cc.Node} forcedTarget
2531      */
2532     setForcedTarget:function (forcedTarget) {
2533         if (this._forcedTarget != forcedTarget)
2534             this._forcedTarget = forcedTarget;
2535     }
2536 });
2537 
2538 /**
2539  * Create an action with the specified action and forced target
2540  * @param {cc.Node} target
2541  * @param {cc.FiniteTimeAction} action
2542  */
2543 cc.TargetedAction.create = function (target, action) {
2544     var retObj = new cc.TargetedAction();
2545     retObj.initWithTarget(target, action);
2546     return retObj;
2547 };
2548