1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies 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 /** Default Action tag
 28  * @constant
 29  * @type {Number}
 30  * @default
 31  */
 32 cc.ACTION_TAG_INVALID = -1;
 33 
 34 /**
 35  * Base class for cc.Action objects.
 36  * @class
 37  *
 38  * @extends cc.Class
 39  *
 40  * @property {cc.Node}  target          - The target will be set with the 'startWithTarget' method. When the 'stop' method is called, target will be set to nil.
 41  * @property {cc.Node}  originalTarget  - The original target of the action.
 42  * @property {Number}   tag             - The tag of the action, can be used to find the action.
 43  */
 44 cc.Action = cc.Class.extend(/** @lends cc.Action# */{
 45     //***********variables*************
 46     originalTarget:null,
 47     target:null,
 48     tag:cc.ACTION_TAG_INVALID,
 49 
 50     //**************Public Functions***********
 51 
 52     /**
 53      * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
 54      */
 55     ctor:function () {
 56         this.originalTarget = null;
 57         this.target = null;
 58         this.tag = cc.ACTION_TAG_INVALID;
 59     },
 60 
 61     /**
 62      * to copy object with deep copy.
 63      *
 64      * @deprecated since v3.0 please use .clone
 65      *
 66      * @return {cc.Action}
 67      */
 68     copy:function () {
 69         cc.log("copy is deprecated. Please use clone instead.");
 70         return this.clone();
 71     },
 72 
 73     /**
 74      * to copy object with deep copy.
 75      * returns a clone of action.
 76      *
 77      * @return {cc.Action}
 78      */
 79     clone:function () {
 80         var action = new cc.Action();
 81         action.originalTarget = null;
 82         action.target = null;
 83         action.tag = this.tag;
 84         return action;
 85     },
 86 
 87     /**
 88      * return true if the action has finished.
 89      *
 90      * @return {Boolean}
 91      */
 92     isDone:function () {
 93         return true;
 94     },
 95 
 96     /**
 97      * called before the action start. It will also set the target.
 98      *
 99      * @param {cc.Node} target
100      */
101     startWithTarget:function (target) {
102         this.originalTarget = target;
103         this.target = target;
104     },
105 
106     /**
107      * called after the action has finished. It will set the 'target' to nil. <br />
108      * IMPORTANT: You should never call "action stop" manually. Instead, use: "target.stopAction(action);"
109      */
110     stop:function () {
111         this.target = null;
112     },
113 
114     /**
115      * called every frame with it's delta time. <br />
116      * DON'T override unless you know what you are doing.
117      *
118      * @param {Number} dt
119      */
120     step:function (dt) {
121         cc.log("[Action step]. override me");
122     },
123 
124     /**
125      * Called once per frame. Time is the number of seconds of a frame interval.
126      *
127      * @param {Number}  dt
128      */
129     update:function (dt) {
130         cc.log("[Action update]. override me");
131     },
132 
133     /**
134      * get the target.
135      *
136      * @return {cc.Node}
137      */
138     getTarget:function () {
139         return this.target;
140     },
141 
142     /**
143      * The action will modify the target properties.
144      *
145      * @param {cc.Node} target
146      */
147     setTarget:function (target) {
148         this.target = target;
149     },
150 
151     /**
152      * get the original target.
153      *
154      * @return {cc.Node}
155      */
156     getOriginalTarget:function () {
157         return this.originalTarget;
158     },
159 
160     /**
161      * Set the original target, since target can be nil. <br/>
162      * Is the target that were used to run the action.  <br/>
163      * Unless you are doing something complex, like cc.ActionManager, you should NOT call this method. <br/>
164      * The target is 'assigned', it is not 'retained'. <br/>
165      * @param {cc.Node} originalTarget
166      */
167     setOriginalTarget:function (originalTarget) {
168         this.originalTarget = originalTarget;
169     },
170 
171     /**
172      * get tag number.
173      * @return {Number}
174      */
175     getTag:function () {
176         return this.tag;
177     },
178 
179     /**
180      * set tag number.
181      * @param {Number} tag
182      */
183     setTag:function (tag) {
184         this.tag = tag;
185     },
186 
187     /**
188      * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB, <br/>
189      * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. <br/>
190      * This is a hack, and should be removed once JSB fixes the retain/release bug.
191      */
192     retain:function () {
193     },
194 
195     /**
196      * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB, <br/>
197      * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. <br/>
198      * This is a hack, and should be removed once JSB fixes the retain/release bug.
199      */
200     release:function () {
201     }
202 });
203 
204 /**
205  * Allocates and initializes the action.
206  *
207  * @function cc.action
208  * @static
209  * @return {cc.Action}
210  *
211  * @example
212  * // return {cc.Action}
213  * var action = cc.action();
214  */
215 cc.action = function () {
216     return new cc.Action();
217 };
218 
219 /**
220  * Please use cc.action instead. <br/>
221  * Allocates and initializes the action.
222  *
223  * @deprecated since v3.0 please use cc.action() instead.
224  * @static
225  * @returns {cc.Action}
226  */
227 cc.Action.create = cc.action;
228 
229 
230 /**
231  * Base class actions that do have a finite time duration. <br/>
232  * Possible actions: <br/>
233  * - An action with a duration of 0 seconds. <br/>
234  * - An action with a duration of 35.5 seconds.
235  *
236  * Infinite time actions are valid
237  * @class
238  * @extends cc.Action
239  */
240 cc.FiniteTimeAction = cc.Action.extend(/** @lends cc.FiniteTimeAction# */{
241     //! duration in seconds
242     _duration:0,
243 
244     /**
245      * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
246      */
247     ctor:function () {
248         cc.Action.prototype.ctor.call(this);
249         this._duration = 0;
250     },
251 
252     /**
253      * get duration of the action. (seconds)
254      *
255      * @return {Number}
256      */
257     getDuration:function () {
258         return this._duration * (this._times || 1);
259     },
260 
261     /**
262      * set duration of the action. (seconds)
263      *
264      * @param {Number} duration
265      */
266     setDuration:function (duration) {
267         this._duration = duration;
268     },
269 
270     /**
271      * Returns a reversed action. <br />
272      * For example: <br />
273      * - The action will be x coordinates of 0 move to 100. <br />
274      * - The reversed action will be x of 100 move to 0.
275      * - Will be rewritten
276      *
277      * @return {Null}
278      */
279     reverse:function () {
280         cc.log("cocos2d: FiniteTimeAction#reverse: Implement me");
281         return null;
282     },
283 
284     /**
285      * to copy object with deep copy.
286      * returns a clone of action.
287      *
288      * @return {cc.FiniteTimeAction}
289      */
290     clone:function () {
291         return new cc.FiniteTimeAction();
292     }
293 });
294 
295 /**
296  * Changes the speed of an action, making it take longer (speed > 1)
297  * or less (speed < 1) time. <br/>
298  * Useful to simulate 'slow motion' or 'fast forward' effect.
299  *
300  * @warning This action can't be Sequenceable because it is not an cc.IntervalAction
301  * @class
302  * @extends cc.Action
303  * @param {cc.ActionInterval} action
304  * @param {Number} speed
305  */
306 cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{
307     _speed:0.0,
308     _innerAction:null,
309 
310 	/**
311      * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
312 	 * @param {cc.ActionInterval} action
313 	 * @param {Number} speed
314 	 */
315     ctor:function (action, speed) {
316         cc.Action.prototype.ctor.call(this);
317         this._speed = 0;
318         this._innerAction = null;
319 
320 		action && this.initWithAction(action, speed);
321     },
322 
323     /**
324      * Gets the current running speed. <br />
325      * Will get a percentage number, compared to the original speed.
326      *
327      * @return {Number}
328      */
329     getSpeed:function () {
330         return this._speed;
331     },
332 
333     /**
334      * alter the speed of the inner function in runtime.
335      *
336      * @param {Number} speed
337      */
338     setSpeed:function (speed) {
339         this._speed = speed;
340     },
341 
342     /**
343      * initializes the action.
344      *
345      * @param {cc.ActionInterval} action
346      * @param {Number} speed
347      * @return {Boolean}
348      */
349     initWithAction:function (action, speed) {
350         if(!action)
351             throw "cc.Speed.initWithAction(): action must be non nil";
352 
353         this._innerAction = action;
354         this._speed = speed;
355         return true;
356     },
357 
358     /**
359      * to copy object with deep copy.
360      * returns a clone of action.
361      *
362      * @returns {cc.Speed}
363      */
364     clone:function () {
365         var action = new cc.Speed();
366         action.initWithAction(this._innerAction.clone(), this._speed);
367         return action;
368     },
369 
370     /**
371      * called before the action start. It will also set the target.
372      *
373      * @param {cc.Node} target
374      */
375     startWithTarget:function (target) {
376         cc.Action.prototype.startWithTarget.call(this, target);
377         this._innerAction.startWithTarget(target);
378     },
379 
380     /**
381      *  Stop the action.
382      */
383     stop:function () {
384         this._innerAction.stop();
385         cc.Action.prototype.stop.call(this);
386     },
387 
388     /**
389      * called every frame with it's delta time. <br />
390      * DON'T override unless you know what you are doing.
391      *
392      * @param {Number} dt
393      */
394     step:function (dt) {
395         this._innerAction.step(dt * this._speed);
396     },
397 
398     /**
399      * return true if the action has finished.
400      *
401      * @return {Boolean}
402      */
403     isDone:function () {
404         return this._innerAction.isDone();
405     },
406 
407     /**
408      * returns a reversed action. <br />
409      * For example: <br />
410      * - The action will be x coordinates of 0 move to 100. <br />
411      * - The reversed action will be x of 100 move to 0.
412      * - Will be rewritten
413      *
414      * @return {cc.Speed}
415      */
416     reverse:function () {
417         return new cc.Speed(this._innerAction.reverse(), this._speed);
418     },
419 
420     /**
421      * Set inner Action.
422      * @param {cc.ActionInterval} action
423      */
424     setInnerAction:function (action) {
425         if (this._innerAction != action) {
426             this._innerAction = action;
427         }
428     },
429 
430     /**
431      * Get inner Action.
432      *
433      * @return {cc.ActionInterval}
434      */
435     getInnerAction:function () {
436         return this._innerAction;
437     }
438 });
439 
440 /**
441  * creates the speed action.
442  *
443  * @function cc.speed
444  * @param {cc.ActionInterval} action
445  * @param {Number} speed
446  * @return {cc.Speed}
447  */
448 cc.speed = function (action, speed) {
449     return new cc.Speed(action, speed);
450 };
451 
452 /**
453  * Please use cc.speed instead.
454  * creates the action.
455  *
456  * @param {cc.ActionInterval} action
457  * @param {Number} speed
458  * @return {cc.Speed}
459  * @static
460  * @deprecated since v3.0 please use cc.speed() instead.
461  */
462 cc.Speed.create = cc.speed;
463 
464 /**
465  * cc.Follow is an action that "follows" a node.
466  *
467  * @example
468  * //example
469  * //Instead of using cc.Camera as a "follower", use this action instead.
470  * layer.runAction(cc.follow(hero));
471  *
472  * @property {Number}  leftBoundary - world leftBoundary.
473  * @property {Number}  rightBoundary - world rightBoundary.
474  * @property {Number}  topBoundary - world topBoundary.
475  * @property {Number}  bottomBoundary - world bottomBoundary.
476  *
477  * @param {cc.Node} followedNode
478  * @param {cc.Rect} rect
479  * @example
480  * // creates the action with a set boundary
481  * var sprite = new cc.Sprite("spriteFileName");
482  * var followAction = new cc.Follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height));
483  * this.runAction(followAction);
484  *
485  * // creates the action with no boundary set
486  * var sprite = new cc.Sprite("spriteFileName");
487  * var followAction = new cc.Follow(sprite);
488  * this.runAction(followAction);
489  *
490  * @class
491  * @extends cc.Action
492  */
493 cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{
494     // node to follow
495     _followedNode:null,
496     // whether camera should be limited to certain area
497     _boundarySet:false,
498     // if screen size is bigger than the boundary - update not needed
499     _boundaryFullyCovered:false,
500     // fast access to the screen dimensions
501     _halfScreenSize:null,
502     _fullScreenSize:null,
503     _worldRect:null,
504 
505     leftBoundary:0.0,
506     rightBoundary:0.0,
507     topBoundary:0.0,
508     bottomBoundary:0.0,
509 
510 	/**
511      * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. <br />
512 	 * creates the action with a set boundary. <br/>
513 	 * creates the action with no boundary set.
514      * @param {cc.Node} followedNode
515      * @param {cc.Rect} rect
516 	 */
517     ctor:function (followedNode, rect) {
518         cc.Action.prototype.ctor.call(this);
519         this._followedNode = null;
520         this._boundarySet = false;
521 
522         this._boundaryFullyCovered = false;
523         this._halfScreenSize = null;
524         this._fullScreenSize = null;
525 
526         this.leftBoundary = 0.0;
527         this.rightBoundary = 0.0;
528         this.topBoundary = 0.0;
529         this.bottomBoundary = 0.0;
530         this._worldRect = cc.rect(0, 0, 0, 0);
531 
532 		if(followedNode)
533 			rect ? this.initWithTarget(followedNode, rect)
534 				 : this.initWithTarget(followedNode);
535     },
536 
537     /**
538      * to copy object with deep copy.
539      * returns a clone of action.
540      *
541      * @return {cc.Follow}
542      */
543     clone:function () {
544         var action = new cc.Follow();
545         var locRect = this._worldRect;
546         var rect = new cc.Rect(locRect.x, locRect.y, locRect.width, locRect.height);
547         action.initWithTarget(this._followedNode, rect);
548         return action;
549     },
550 
551     /**
552      * Get whether camera should be limited to certain area.
553      *
554      * @return {Boolean}
555      */
556     isBoundarySet:function () {
557         return this._boundarySet;
558     },
559 
560     /**
561      * alter behavior - turn on/off boundary.
562      *
563      * @param {Boolean} value
564      */
565     setBoudarySet:function (value) {
566         this._boundarySet = value;
567     },
568 
569     /**
570      * initializes the action with a set boundary.
571      *
572      * @param {cc.Node} followedNode
573      * @param {cc.Rect} [rect=]
574      * @return {Boolean}
575      */
576     initWithTarget:function (followedNode, rect) {
577         if(!followedNode)
578             throw "cc.Follow.initWithAction(): followedNode must be non nil";
579 
580         var _this = this;
581         rect = rect || cc.rect(0, 0, 0, 0);
582         _this._followedNode = followedNode;
583         _this._worldRect = rect;
584 
585         _this._boundarySet = !cc._rectEqualToZero(rect);
586 
587         _this._boundaryFullyCovered = false;
588 
589         var winSize = cc.director.getWinSize();
590         _this._fullScreenSize = cc.p(winSize.width, winSize.height);
591         _this._halfScreenSize = cc.pMult(_this._fullScreenSize, 0.5);
592 
593         if (_this._boundarySet) {
594             _this.leftBoundary = -((rect.x + rect.width) - _this._fullScreenSize.x);
595             _this.rightBoundary = -rect.x;
596             _this.topBoundary = -rect.y;
597             _this.bottomBoundary = -((rect.y + rect.height) - _this._fullScreenSize.y);
598 
599             if (_this.rightBoundary < _this.leftBoundary) {
600                 // screen width is larger than world's boundary width
601                 //set both in the middle of the world
602                 _this.rightBoundary = _this.leftBoundary = (_this.leftBoundary + _this.rightBoundary) / 2;
603             }
604             if (_this.topBoundary < _this.bottomBoundary) {
605                 // screen width is larger than world's boundary width
606                 //set both in the middle of the world
607                 _this.topBoundary = _this.bottomBoundary = (_this.topBoundary + _this.bottomBoundary) / 2;
608             }
609 
610             if ((_this.topBoundary == _this.bottomBoundary) && (_this.leftBoundary == _this.rightBoundary))
611                 _this._boundaryFullyCovered = true;
612         }
613         return true;
614     },
615 
616     /**
617      * called every frame with it's delta time. <br />
618      * DON'T override unless you know what you are doing.
619      *
620      * @param {Number} dt
621      */
622     step:function (dt) {
623         var tempPosX = this._followedNode.x;
624         var tempPosY = this._followedNode.y;
625         tempPosX = this._halfScreenSize.x - tempPosX;
626         tempPosY = this._halfScreenSize.y - tempPosY;
627 
628         //TODO Temporary treatment - The dirtyFlag symbol error
629         this.target._renderCmd._dirtyFlag = 0;
630 
631         if (this._boundarySet) {
632             // whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased
633             if (this._boundaryFullyCovered)
634                 return;
635 
636 	        this.target.setPosition(cc.clampf(tempPosX, this.leftBoundary, this.rightBoundary), cc.clampf(tempPosY, this.bottomBoundary, this.topBoundary));
637         } else {
638             this.target.setPosition(tempPosX, tempPosY);
639         }
640     },
641 
642     /**
643      * Return true if the action has finished.
644      *
645      * @return {Boolean}
646      */
647     isDone:function () {
648         return ( !this._followedNode.running );
649     },
650 
651     /**
652      * Stop the action.
653      */
654     stop:function () {
655         this.target = null;
656         cc.Action.prototype.stop.call(this);
657     }
658 });
659 
660 /**
661  * creates the action with a set boundary. <br/>
662  * creates the action with no boundary set.
663  *
664  * @function
665  * @param {cc.Node} followedNode
666  * @param {cc.Rect} rect
667  * @return {cc.Follow|Null} returns the cc.Follow object on success
668  * @example
669  * // example
670  * // creates the action with a set boundary
671  * var sprite = new cc.Sprite("spriteFileName");
672  * var followAction = cc.follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height));
673  * this.runAction(followAction);
674  *
675  * // creates the action with no boundary set
676  * var sprite = new cc.Sprite("spriteFileName");
677  * var followAction = cc.follow(sprite);
678  * this.runAction(followAction);
679  */
680 cc.follow = function (followedNode, rect) {
681     return new cc.Follow(followedNode, rect);
682 };
683 
684 /**
685  * Please use cc.follow instead.
686  * creates the action with a set boundary. <br/>
687  * creates the action with no boundary set.
688  * @param {cc.Node} followedNode
689  * @param {cc.Rect} rect
690  * @return {cc.Follow|Null} returns the cc.Follow object on success
691  * @static
692  * @deprecated since v3.0 please cc.follow() instead.
693  */
694 cc.Follow.create = cc.follow;
695