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 In an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 0 to 255.<br/>
1821  * The "reverse" of this action is FadeOut
1822  * @class
1823  * @extends cc.ActionInterval
1824  */
1825 cc.FadeIn = cc.ActionInterval.extend(/** @lends cc.FadeIn# */{
1826     /**
1827      * @param {Number} time time in seconds
1828      */
1829     update:function (time) {
1830         if (this._target.RGBAProtocol) {
1831             this._target.setOpacity(255 * time);
1832         }
1833     },
1834 
1835     /**
1836      * @return {cc.ActionInterval}
1837      */
1838     reverse:function () {
1839         return cc.FadeOut.create(this._duration);
1840     },
1841 
1842     /**
1843      * returns a new clone of the action
1844      * @returns {cc.FadeIn}
1845      */
1846     clone:function () {
1847         var action = new cc.FadeIn();
1848         action.initWithDuration(this._duration);
1849         return action;
1850     }
1851 });
1852 
1853 /**
1854  * @param {Number} duration duration in seconds
1855  * @return {cc.FadeIn}
1856  * @example
1857  * //example
1858  * var action = cc.FadeIn.create(1.0);
1859  */
1860 cc.FadeIn.create = function (duration) {
1861     var action = new cc.FadeIn();
1862     action.initWithDuration(duration);
1863     return action;
1864 };
1865 
1866 
1867 /** Fades Out an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 255 to 0.
1868  * The "reverse" of this action is FadeIn
1869  * @class
1870  * @extends cc.ActionInterval
1871  */
1872 cc.FadeOut = cc.ActionInterval.extend(/** @lends cc.FadeOut# */{
1873     /**
1874      * @param {Number} time  time in seconds
1875      */
1876     update:function (time) {
1877         if (this._target.RGBAProtocol) {
1878             this._target.setOpacity(255 * (1 - time));
1879         }
1880     },
1881 
1882     /**
1883      * @return {cc.ActionInterval}
1884      */
1885     reverse:function () {
1886         return cc.FadeIn.create(this._duration);
1887     },
1888 
1889     /**
1890      * returns a new clone of the action
1891      * @returns {cc.FadeOut}
1892      */
1893     clone:function () {
1894         var action = new cc.FadeOut();
1895         action.initWithDuration(this._duration);
1896         return action;
1897     }
1898 });
1899 
1900 /**
1901  * @param {Number} d  duration in seconds
1902  * @return {cc.FadeOut}
1903  * @example
1904  * // example
1905  * var action = cc.FadeOut.create(1.0);
1906  */
1907 cc.FadeOut.create = function (d) {
1908     var action = new cc.FadeOut();
1909     action.initWithDuration(d);
1910     return action;
1911 };
1912 
1913 /** Fades an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from the current value to a custom one.
1914  * @warning This action doesn't support "reverse"
1915  * @class
1916  * @extends cc.ActionInterval
1917  */
1918 cc.FadeTo = cc.ActionInterval.extend(/** @lends cc.FadeTo# */{
1919     _toOpacity:null,
1920     _fromOpacity:null,
1921 
1922     ctor:function () {
1923         cc.ActionInterval.prototype.ctor.call(this);
1924         this._toOpacity = 0;
1925         this._fromOpacity = 0;
1926     },
1927 
1928     /**
1929      * @param {Number} duration  duration in seconds
1930      * @param {Number} opacity
1931      * @return {Boolean}
1932      */
1933     initWithDuration:function (duration, opacity) {
1934         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
1935             this._toOpacity = opacity;
1936             return true;
1937         }
1938         return false;
1939     },
1940 
1941     /**
1942      * returns a new clone of the action
1943      * @returns {cc.FadeTo}
1944      */
1945     clone:function () {
1946         var action = new cc.FadeTo();
1947         action.initWithDuration(this._duration, this._toOpacity);
1948         return action;
1949     },
1950 
1951     /**
1952      * @param {Number} time time in seconds
1953      */
1954     update:function (time) {
1955         if (this._target.RGBAProtocol) {
1956             this._target.setOpacity((this._fromOpacity + (this._toOpacity - this._fromOpacity) * time));
1957         }
1958     },
1959 
1960     /**
1961      * @param {cc.Sprite} target
1962      */
1963     startWithTarget:function (target) {
1964         cc.ActionInterval.prototype.startWithTarget.call(this, target);
1965         if(this._target.RGBAProtocol){
1966             this._fromOpacity = target.getOpacity();
1967         }
1968     }
1969 });
1970 
1971 /**
1972  * @param {Number} duration
1973  * @param {Number} opacity 0-255, 0 is transparent
1974  * @return {cc.FadeTo}
1975  * @example
1976  * // example
1977  * var action = cc.FadeTo.create(1.0, 0);
1978  */
1979 cc.FadeTo.create = function (duration, opacity) {
1980     var fadeTo = new cc.FadeTo();
1981     fadeTo.initWithDuration(duration, opacity);
1982     return fadeTo;
1983 };
1984 
1985 /** Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one.
1986  * @warning This action doesn't support "reverse"
1987  * @class
1988  * @extends cc.ActionInterval
1989  */
1990 cc.TintTo = cc.ActionInterval.extend(/** @lends cc.TintTo# */{
1991     _to:null,
1992     _from:null,
1993 
1994     ctor:function () {
1995         cc.ActionInterval.prototype.ctor.call(this);
1996         this._to = cc.c3b(0, 0, 0);
1997         this._from = cc.c3b(0, 0, 0);
1998     },
1999 
2000     /**
2001      * @param {Number} duration
2002      * @param {Number} red 0-255
2003      * @param {Number} green 0-255
2004      * @param {Number} blue 0-255
2005      * @return {Boolean}
2006      */
2007     initWithDuration:function (duration, red, green, blue) {
2008         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
2009             this._to = cc.c3b(red, green, blue);
2010             return true;
2011         }
2012         return false;
2013     },
2014 
2015     /**
2016      * returns a new clone of the action
2017      * @returns {cc.TintTo}
2018      */
2019     clone:function () {
2020         var action = new cc.TintTo();
2021         var locTo = this._to;
2022         action.initWithDuration(this._duration, locTo.r, locTo.g, locTo.b);
2023         return action;
2024     },
2025 
2026     /**
2027      * @param {cc.Sprite} target
2028      */
2029     startWithTarget:function (target) {
2030         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2031         if (this._target.RGBAProtocol) {
2032             this._from = this._target.getColor();
2033         }
2034     },
2035 
2036     /**
2037      * @param {Number} time time in seconds
2038      */
2039     update:function (time) {
2040         var locFrom = this._from, locTo = this._to;
2041         if (this._target.RGBAProtocol) {
2042             this._target.setColor(cc.c3b(locFrom.r + (locTo.r - locFrom.r) * time,
2043                 (locFrom.g + (locTo.g - locFrom.g) * time), (locFrom.b + (locTo.b - locFrom.b) * time)));
2044         }
2045     }
2046 });
2047 
2048 /**
2049  * @param {Number} duration
2050  * @param {Number} red 0-255
2051  * @param {Number} green  0-255
2052  * @param {Number} blue 0-255
2053  * @return {cc.TintTo}
2054  * @example
2055  * // example
2056  * var action = cc.TintTo.create(2, 255, 0, 255);
2057  */
2058 cc.TintTo.create = function (duration, red, green, blue) {
2059     var tintTo = new cc.TintTo();
2060     tintTo.initWithDuration(duration, red, green, blue);
2061     return tintTo;
2062 };
2063 
2064 
2065 /**  Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one.
2066  * @class
2067  * @extends cc.ActionInterval
2068  */
2069 cc.TintBy = cc.ActionInterval.extend(/** @lends cc.TintBy# */{
2070     _deltaR:0,
2071     _deltaG:0,
2072     _deltaB:0,
2073 
2074     _fromR:0,
2075     _fromG:0,
2076     _fromB:0,
2077 
2078     ctor:function () {
2079         cc.ActionInterval.prototype.ctor.call(this);
2080         this._deltaR = 0;
2081         this._deltaG = 0;
2082         this._deltaB = 0;
2083         this._fromR = 0;
2084         this._fromG = 0;
2085         this._fromB = 0;
2086     },
2087 
2088     /**
2089      * @param {Number} duration
2090      * @param {Number} deltaRed 0-255
2091      * @param {Number} deltaGreen 0-255
2092      * @param {Number} deltaBlue 0-255
2093      * @return {Boolean}
2094      */
2095     initWithDuration:function (duration, deltaRed, deltaGreen, deltaBlue) {
2096         if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
2097             this._deltaR = deltaRed;
2098             this._deltaG = deltaGreen;
2099             this._deltaB = deltaBlue;
2100             return true;
2101         }
2102         return false;
2103     },
2104 
2105     /**
2106      * returns a new clone of the action
2107      * @returns {cc.TintBy}
2108      */
2109     clone:function () {
2110         var action = new cc.TintBy();
2111         action.initWithDuration(this._duration, this._deltaR, this._deltaG, this._deltaB);
2112         return action;
2113     },
2114 
2115     /**
2116      * @param {cc.Sprite} target
2117      */
2118     startWithTarget:function (target) {
2119         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2120         if (target.RGBAProtocol) {
2121             var color = target.getColor();
2122             this._fromR = color.r;
2123             this._fromG = color.g;
2124             this._fromB = color.b;
2125         }
2126     },
2127 
2128     /**
2129      * @param {Number} time time in seconds
2130      */
2131     update:function (time) {
2132         if (this._target.RGBAProtocol) {
2133             this._target.setColor(cc.c3b((this._fromR + this._deltaR * time),
2134                 (this._fromG + this._deltaG * time),
2135                 (this._fromB + this._deltaB * time)));
2136         }
2137     },
2138 
2139     /**
2140      * @return {cc.ActionInterval}
2141      */
2142     reverse:function () {
2143         return cc.TintBy.create(this._duration, -this._deltaR, -this._deltaG, -this._deltaB);
2144     }
2145 });
2146 
2147 /**
2148  * @param {Number} duration  duration in seconds
2149  * @param {Number} deltaRed
2150  * @param {Number} deltaGreen
2151  * @param {Number} deltaBlue
2152  * @return {cc.TintBy}
2153  * @example
2154  * // example
2155  * var action = cc.TintBy.create(2, -127, -255, -127);
2156  */
2157 cc.TintBy.create = function (duration, deltaRed, deltaGreen, deltaBlue) {
2158     var tintBy = new cc.TintBy();
2159     tintBy.initWithDuration(duration, deltaRed, deltaGreen, deltaBlue);
2160     return tintBy;
2161 };
2162 
2163 /** Delays the action a certain amount of seconds
2164  * @class
2165  * @extends cc.ActionInterval
2166  */
2167 cc.DelayTime = cc.ActionInterval.extend(/** @lends cc.DelayTime# */{
2168     /**
2169      * @param {Number} time time in seconds
2170      */
2171     update:function (time) {
2172     },
2173 
2174     /**
2175      * @return {cc.ActionInterval}
2176      */
2177     reverse:function () {
2178         return cc.DelayTime.create(this._duration);
2179     },
2180 
2181     /**
2182      * returns a new clone of the action
2183      * @returns {cc.DelayTime}
2184      */
2185     clone:function () {
2186         var action = new cc.DelayTime();
2187         action.initWithDuration(this._duration);
2188         return action;
2189     }
2190 });
2191 
2192 /**
2193  * @param {Number} d duration in seconds
2194  * @return {cc.DelayTime}
2195  * @example
2196  * // example
2197  * var delay = cc.DelayTime.create(1);
2198  */
2199 cc.DelayTime.create = function (d) {
2200     var action = new cc.DelayTime();
2201     action.initWithDuration(d);
2202     return action;
2203 };
2204 
2205 /**
2206  * Executes an action in reverse order, from time=duration to time=0
2207  * @warning Use this action carefully. This action is not
2208  * sequenceable. Use it as the default "reversed" method
2209  * of your own actions, but using it outside the "reversed"
2210  * scope is not recommended.
2211  * @class
2212  * @extends cc.ActionInterval
2213  */
2214 cc.ReverseTime = cc.ActionInterval.extend(/** @lends cc.ReverseTime# */{
2215     _other:null,
2216 
2217     ctor:function () {
2218         cc.ActionInterval.prototype.ctor.call(this);
2219         this._other = null;
2220     },
2221 
2222     /**
2223      * @param {cc.FiniteTimeAction} action
2224      * @return {Boolean}
2225      */
2226     initWithAction:function (action) {
2227         if(!action)
2228             throw "cc.ReverseTime.initWithAction(): action must be non null";
2229         if(action == this._other)
2230             throw "cc.ReverseTime.initWithAction(): the action was already passed in.";
2231 
2232         if (cc.ActionInterval.prototype.initWithDuration.call(this, action.getDuration())) {
2233             // Don't leak if action is reused
2234             this._other = action;
2235             return true;
2236         }
2237         return false;
2238     },
2239 
2240     /**
2241      * returns a new clone of the action
2242      * @returns {cc.ReverseTime}
2243      */
2244     clone:function () {
2245         var action = new cc.ReverseTime();
2246         action.initWithAction(this._other.clone());
2247         return action;
2248     },
2249 
2250     /**
2251      * @param {cc.Node} target
2252      */
2253     startWithTarget:function (target) {
2254         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2255         this._other.startWithTarget(target);
2256     },
2257 
2258     /**
2259      * @param {Number} time time in seconds
2260      */
2261     update:function (time) {
2262         if (this._other)
2263             this._other.update(1 - time);
2264     },
2265 
2266     /**
2267      * @return {cc.ActionInterval}
2268      */
2269     reverse:function () {
2270         return this._other.clone();
2271     },
2272 
2273     /**
2274      * Stop the action
2275      */
2276     stop:function () {
2277         this._other.stop();
2278         cc.Action.prototype.stop.call(this);
2279     }
2280 });
2281 
2282 /**
2283  * @param {cc.FiniteTimeAction} action
2284  * @return {cc.ReverseTime}
2285  * @example
2286  * // example
2287  *  var reverse = cc.ReverseTime.create(this);
2288  */
2289 cc.ReverseTime.create = function (action) {
2290     var reverseTime = new cc.ReverseTime();
2291     reverseTime.initWithAction(action);
2292     return reverseTime;
2293 };
2294 
2295 
2296 /**  Animates a sprite given the name of an Animation
2297  * @class
2298  * @extends cc.ActionInterval
2299  */
2300 cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{
2301     _animation:null,
2302     _nextFrame:0,
2303     _origFrame:null,
2304     _executedLoops:0,
2305     _splitTimes:null,
2306 
2307     ctor:function () {
2308         cc.ActionInterval.prototype.ctor.call(this);
2309         this._animation = null;
2310         this._nextFrame = 0;
2311         this._origFrame = null;
2312         this._executedLoops = 0;
2313         this._splitTimes = [];
2314     },
2315 
2316     /**
2317      * @return {cc.Animation}
2318      */
2319     getAnimation:function () {
2320         return this._animation;
2321     },
2322 
2323     /**
2324      * @param {cc.Animation} animation
2325      */
2326     setAnimation:function (animation) {
2327         this._animation = animation;
2328     },
2329 
2330     /**
2331      * @param {cc.Animation} animation
2332      * @return {Boolean}
2333      */
2334     initWithAnimation:function (animation) {
2335         if(!animation)
2336             throw "cc.Animate.initWithAnimation(): animation must be non-NULL";
2337         var singleDuration = animation.getDuration();
2338         if (this.initWithDuration(singleDuration * animation.getLoops())) {
2339             this._nextFrame = 0;
2340             this.setAnimation(animation);
2341 
2342             this._origFrame = null;
2343             this._executedLoops = 0;
2344             var locTimes = this._splitTimes;
2345             locTimes.length = 0;
2346 
2347             var accumUnitsOfTime = 0;
2348             var newUnitOfTimeValue = singleDuration / animation.getTotalDelayUnits();
2349 
2350             var frames = animation.getFrames();
2351             cc.ArrayVerifyType(frames, cc.AnimationFrame);
2352 
2353             for (var i = 0; i < frames.length; i++) {
2354                 var frame = frames[i];
2355                 var value = (accumUnitsOfTime * newUnitOfTimeValue) / singleDuration;
2356                 accumUnitsOfTime += frame.getDelayUnits();
2357                 locTimes.push(value);
2358             }
2359             return true;
2360         }
2361         return false;
2362     },
2363 
2364     /**
2365      * returns a new clone of the action
2366      * @returns {cc.Animate}
2367      */
2368     clone:function () {
2369         var action = new cc.Animate();
2370         action.initWithAnimation(this._animation.clone());
2371         return action;
2372     },
2373 
2374     /**
2375      * @param {cc.Sprite} target
2376      */
2377     startWithTarget:function (target) {
2378         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2379         if (this._animation.getRestoreOriginalFrame())
2380             this._origFrame = target.displayFrame();
2381         this._nextFrame = 0;
2382         this._executedLoops = 0;
2383     },
2384 
2385     /**
2386      * @param {Number} time
2387      */
2388     update:function (time) {
2389         // if t==1, ignore. Animation should finish with t==1
2390         if (time < 1.0) {
2391             time *= this._animation.getLoops();
2392 
2393             // new loop?  If so, reset frame counter
2394             var loopNumber = 0 | time;
2395             if (loopNumber > this._executedLoops) {
2396                 this._nextFrame = 0;
2397                 this._executedLoops++;
2398             }
2399 
2400             // new t for animations
2401             time = time % 1.0;
2402         }
2403 
2404         var frames = this._animation.getFrames();
2405         var numberOfFrames = frames.length, locSplitTimes = this._splitTimes;
2406         for (var i = this._nextFrame; i < numberOfFrames; i++) {
2407             if (locSplitTimes[i] <= time) {
2408                 this._target.setDisplayFrame(frames[i].getSpriteFrame());
2409                 this._nextFrame = i + 1;
2410             } else {
2411                 // Issue 1438. Could be more than one frame per tick, due to low frame rate or frame delta < 1/FPS
2412                 break;
2413             }
2414         }
2415     },
2416 
2417     /**
2418      * @return {cc.ActionInterval}
2419      */
2420     reverse:function () {
2421         var locAnimation = this._animation;
2422         var oldArray = locAnimation.getFrames();
2423         var newArray = [];
2424         cc.ArrayVerifyType(oldArray, cc.AnimationFrame);
2425         if (oldArray.length > 0) {
2426             for (var i = oldArray.length - 1; i >= 0; i--) {
2427                 var element = oldArray[i];
2428                 if (!element)
2429                     break;
2430                 newArray.push(element.clone());
2431             }
2432         }
2433         var newAnim = cc.Animation.createWithAnimationFrames(newArray, locAnimation.getDelayPerUnit(), locAnimation.getLoops());
2434         newAnim.setRestoreOriginalFrame(locAnimation.getRestoreOriginalFrame());
2435         return cc.Animate.create(newAnim);
2436     },
2437 
2438     /**
2439      * stop the action
2440      */
2441     stop:function () {
2442         if (this._animation.getRestoreOriginalFrame() && this._target)
2443             this._target.setDisplayFrame(this._origFrame);
2444         cc.Action.prototype.stop.call(this);
2445     }
2446 });
2447 
2448 /**
2449  * create the animate with animation
2450  * @param {cc.Animation} animation
2451  * @return {cc.Animate}
2452  * @example
2453  * // example
2454  * // create the animation with animation
2455  * var anim = cc.Animate.create(dance_grey);
2456  */
2457 cc.Animate.create = function (animation) {
2458     var animate = new cc.Animate();
2459     animate.initWithAnimation(animation);
2460     return animate;
2461 };
2462 
2463 /**
2464  * <p>
2465  *     Overrides the target of an action so that it always runs on the target<br/>
2466  *     specified at action creation rather than the one specified by runAction.
2467  * </p>
2468  * @class
2469  * @extends cc.ActionInterval
2470  */
2471 cc.TargetedAction = cc.ActionInterval.extend(/** @lends cc.TargetedAction# */{
2472     _action:null,
2473     _forcedTarget:null,
2474 
2475     ctor:function () {
2476         cc.ActionInterval.prototype.ctor.call(this);
2477         this._action = null;
2478         this._forcedTarget = null;
2479     },
2480 
2481     /**
2482      * Init an action with the specified action and forced target
2483      * @param {cc.Node} target
2484      * @param {cc.FiniteTimeAction} action
2485      * @return {Boolean}
2486      */
2487     initWithTarget:function (target, action) {
2488         if (this.initWithDuration(action.getDuration())) {
2489             this._forcedTarget = target;
2490             this._action = action;
2491             return true;
2492         }
2493         return false;
2494     },
2495 
2496     /**
2497      * returns a new clone of the action
2498      * @returns {cc.TargetedAction}
2499      */
2500     clone:function () {
2501         var action = new cc.TargetedAction();
2502         action.initWithTarget(this._forcedTarget, this._action.clone());
2503         return action;
2504     },
2505 
2506     startWithTarget:function (target) {
2507         cc.ActionInterval.prototype.startWithTarget.call(this, target);
2508         this._action.startWithTarget(this._forcedTarget);
2509     },
2510 
2511     stop:function () {
2512         this._action.stop();
2513     },
2514 
2515     update:function (time) {
2516         this._action.update(time);
2517     },
2518 
2519     /**
2520      * return the target that the action will be forced to run with
2521      * @return {cc.Node}
2522      */
2523     getForcedTarget:function () {
2524         return this._forcedTarget;
2525     },
2526 
2527     /**
2528      * set the target that the action will be forced to run with
2529      * @param {cc.Node} forcedTarget
2530      */
2531     setForcedTarget:function (forcedTarget) {
2532         if (this._forcedTarget != forcedTarget)
2533             this._forcedTarget = forcedTarget;
2534     }
2535 });
2536 
2537 /**
2538  * Create an action with the specified action and forced target
2539  * @param {cc.Node} target
2540  * @param {cc.FiniteTimeAction} action
2541  */
2542 cc.TargetedAction.create = function (target, action) {
2543     var retObj = new cc.TargetedAction();
2544     retObj.initWithTarget(target, action);
2545     return retObj;
2546 };
2547