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 /**
 28  * <p>
 29  *    cc.AnimationFrame
 30  *    A frame of the animation. It contains information like:
 31  *       - sprite frame name
 32  *       - # of delay units.
 33  *       - offset
 34  * </p>
 35  * @class
 36  * @extends cc.Class
 37  */
 38 cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{
 39     _spriteFrame:null,
 40     _delayPerUnit:0,
 41     _userInfo:null,
 42 
 43     /**
 44      * Constructor of cc.AnimationFrame
 45      * @param spriteFrame
 46      * @param delayUnits
 47      * @param userInfo
 48      * @returns {AnimationFrame}
 49      */
 50     ctor:function (spriteFrame, delayUnits, userInfo) {
 51         this._spriteFrame = spriteFrame || null;
 52         this._delayPerUnit = delayUnits || 0;
 53         this._userInfo = userInfo || null;
 54     },
 55 
 56     clone: function(){
 57         var frame = new cc.AnimationFrame();
 58         frame.initWithSpriteFrame(this._spriteFrame.clone(), this._delayPerUnit, this._userInfo);
 59         return frame;
 60     },
 61 
 62     copyWithZone:function (pZone) {
 63         return cc.clone(this);
 64     },
 65 
 66     copy:function (pZone) {
 67         var newFrame = new cc.AnimationFrame();
 68         newFrame.initWithSpriteFrame(this._spriteFrame.clone(), this._delayPerUnit, this._userInfo);
 69         return newFrame;
 70     },
 71 
 72     /**
 73      * initializes the animation frame with a spriteframe, number of delay units and a notification user info
 74      * @param {cc.SpriteFrame} spriteFrame
 75      * @param {Number} delayUnits
 76      * @param {object} userInfo
 77      */
 78     initWithSpriteFrame:function (spriteFrame, delayUnits, userInfo) {
 79         this._spriteFrame = spriteFrame;
 80         this._delayPerUnit = delayUnits;
 81         this._userInfo = userInfo;
 82 
 83         return true;
 84     },
 85 
 86     /**
 87      * cc.SpriteFrameName to be used
 88      * @return {cc.SpriteFrame}
 89      */
 90     getSpriteFrame:function () {
 91         return this._spriteFrame;
 92     },
 93 
 94     /**
 95      * cc.SpriteFrameName to be used
 96      * @param {cc.SpriteFrame} spriteFrame
 97      */
 98     setSpriteFrame:function (spriteFrame) {
 99         this._spriteFrame = spriteFrame;
100     },
101 
102     /**
103      * how many units of time the frame takes getter
104      * @return {Number}
105      */
106     getDelayUnits:function () {
107         return this._delayPerUnit;
108     },
109 
110     /**
111      *  how many units of time the frame takes setter
112      * @param delayUnits
113      */
114     setDelayUnits:function (delayUnits) {
115         this._delayPerUnit = delayUnits;
116     },
117 
118     /**
119      *  <p>A cc.AnimationFrameDisplayedNotification notification will be broadcasted when the frame is displayed with this dictionary as UserInfo.<br/>
120      *  If UserInfo is nil, then no notification will be broadcasted. </p>
121      * @return {object}
122      */
123     getUserInfo:function () {
124         return this._userInfo;
125     },
126 
127     /**
128      * @param {object} userInfo
129      */
130     setUserInfo:function (userInfo) {
131         this._userInfo = userInfo;
132     }
133 });
134 
135 /**
136  * Creates an animation frame.
137  * @deprecated
138  * @param {cc.SpriteFrame} spriteFrame
139  * @param {Number} delayUnits
140  * @param {object} userInfo
141  * @example
142  *
143  */
144 cc.AnimationFrame.create = function(spriteFrame,delayUnits,userInfo){
145     return new cc.AnimationFrame(spriteFrame,delayUnits,userInfo);
146 };
147 
148 /**
149  * <p>
150  *     A cc.Animation object is used to perform animations on the cc.Sprite objects.<br/>
151  *     <br/>
152  *      The cc.Animation object contains cc.SpriteFrame objects, and a possible delay between the frames. <br/>
153  *      You can animate a cc.Animation object by using the cc.Animate action. Example:  <br/>
154  * </p>
155  * @class
156  * @extends cc.Class
157  *
158  * @example
159  * //create an animation object
160  * var animation = cc.Animation.create();
161  *
162  * //add a sprite frame to this animation
163  * animation.addFrameWithFile("grossini_dance_01.png");
164  *
165  * //create an animate with this animation
166  * var action = cc.Animate.create(animation);
167  *
168  * //run animate
169  * this._grossini.runAction(action);
170  */
171 cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{
172     _frames:null,
173     _loops:0,
174     _restoreOriginalFrame:false,
175     _duration:0,
176     _delayPerUnit:0,
177     _totalDelayUnits:0,
178 
179 	/**
180 	 * Creates an animation.
181 	 * Constructor of cc.Animation
182 	 * @param {Array} frames
183 	 * @param {Number} delay
184 	 * @param {Number} [loops=1]
185 	 * @example
186 	 * // 1. Creates an empty animation
187 	 * var animation1 = new cc.Animation();
188 	 *
189 	 * // 2. Create an animation with sprite frames, delay and loops.
190 	 * var spriteFrames = [];
191 	 * var frame = cache.getSpriteFrame("grossini_dance_01.png");
192 	 * spriteFrames.push(frame);
193 	 * var animation1 = new cc.Animation(spriteFrames);
194 	 * var animation2 = new cc.Animation(spriteFrames, 0.2);
195 	 * var animation2 = new cc.Animation(spriteFrames, 0.2, 2);
196 	 *
197 	 * // 3. Create an animation with animation frames, delay and loops.
198 	 * var animationFrames = [];
199 	 * var frame =  new cc.AnimationFrame();
200 	 * animationFrames.push(frame);
201 	 * var animation1 = new cc.Animation(animationFrames);
202 	 * var animation2 = new cc.Animation(animationFrames, 0.2);
203 	 * var animation3 = new cc.Animation(animationFrames, 0.2, 2);
204 	 */
205     ctor:function (frames, delay, loops) {
206         this._frames = [];
207 
208 		if (frames === undefined) {
209 			this.initWithSpriteFrames(null, 0);
210 		} else {
211 			var frame0 = frames[0];
212 			if(frame0){
213 				if (frame0 instanceof cc.SpriteFrame) {
214 					//init with sprite frames , delay and loops.
215 					this.initWithSpriteFrames(frames, delay, loops);
216 				}else if(frame0 instanceof cc.AnimationFrame) {
217 					//init with sprite frames , delay and loops.
218 					this.initWithAnimationFrames(frames, delay, loops);
219 				}
220 			}
221 		}
222     },
223 
224     // attributes
225 
226     /**
227      * return array of CCAnimationFrames
228      * @return {Array}
229      */
230     getFrames:function () {
231         return this._frames;
232     },
233 
234     /**
235      * array of CCAnimationFrames setter
236      * @param {Array} frames
237      */
238     setFrames:function (frames) {
239         this._frames = frames;
240     },
241 
242     /**
243      * adds a frame to a cc.Animation  The frame will be added with one "delay unit".
244      * @param {cc.SpriteFrame} frame
245      */
246     addSpriteFrame:function (frame) {
247         var animFrame = new cc.AnimationFrame();
248 
249         animFrame.initWithSpriteFrame(frame, 1, null);
250         this._frames.push(animFrame);
251         // update duration
252         this._totalDelayUnits++;
253     },
254 
255     /**
256      * Adds a frame with an image filename. Internally it will create a cc.SpriteFrame and it will add it. The frame will be added with one "delay unit".
257      * @param {String} fileName
258      */
259     addSpriteFrameWithFile:function (fileName) {
260         var texture = cc.textureCache.addImage(fileName);
261         var rect = cc.rect(0, 0, 0, 0);
262         rect.width = texture.width;
263         rect.height = texture.height;
264         var frame = cc.SpriteFrame.create(texture, rect);
265         this.addSpriteFrame(frame);
266     },
267 
268     /**
269      * Adds a frame with a texture and a rect. Internally it will create a cc.SpriteFrame and it will add it. The frame will be added with one "delay unit".
270      * @param {cc.Texture2D} texture
271      * @param {cc.Rect} rect
272      */
273     addSpriteFrameWithTexture:function (texture, rect) {
274         var pFrame = cc.SpriteFrame.create(texture, rect);
275         this.addSpriteFrame(pFrame);
276     },
277 
278     /**
279      * Initializes a cc.Animation with cc.AnimationFrame
280      * @param {Array} arrayOfAnimationFrames
281      * @param {Number} delayPerUnit
282      * @param {Number} [loops=1]
283      */
284     initWithAnimationFrames:function (arrayOfAnimationFrames, delayPerUnit, loops) {
285         cc.arrayVerifyType(arrayOfAnimationFrames, cc.AnimationFrame);
286 
287         this._delayPerUnit = delayPerUnit;
288         this._loops = loops === undefined ? 1 : loops;
289         this._totalDelayUnits = 0;
290 
291         var locFrames = this._frames;
292         locFrames.length = 0;
293         for (var i = 0; i < arrayOfAnimationFrames.length; i++) {
294             var animFrame = arrayOfAnimationFrames[i];
295             locFrames.push(animFrame);
296             this._totalDelayUnits += animFrame.getDelayUnits();
297         }
298 
299         return true;
300     },
301 
302     clone: function(){
303         var animation = new cc.Animation();
304         animation.initWithAnimationFrames(this._copyFrames(), this._delayPerUnit, this._loops);
305         animation.setRestoreOriginalFrame(this._restoreOriginalFrame);
306         return animation;
307     },
308 
309     /**
310      * @param {cc.Animation} pZone
311      */
312     copyWithZone:function (pZone) {
313         var pCopy = new cc.Animation();
314         pCopy.initWithAnimationFrames(this._copyFrames(), this._delayPerUnit, this._loops);
315         pCopy.setRestoreOriginalFrame(this._restoreOriginalFrame);
316         return pCopy;
317     },
318 
319     _copyFrames:function(){
320        var copyFrames = [];
321         for(var i = 0; i< this._frames.length;i++)
322             copyFrames.push(this._frames[i].clone());
323         return copyFrames;
324     },
325 
326     copy:function (pZone) {
327         return this.copyWithZone(null);
328     },
329 
330     /**
331      * return how many times the animation is going to loop. 0 means animation is not animated. 1, animation is executed one time, ...
332      * @return {Number}
333      */
334     getLoops:function () {
335         return this._loops;
336     },
337 
338     /**
339      * set how many times the animation is going to loop. 0 means animation is not animated. 1, animation is executed one time, ...
340      * @param {Number} value
341      */
342     setLoops:function (value) {
343         this._loops = value;
344     },
345 
346     /**
347      * whether or not it shall restore the original frame when the animation finishes
348      * @param {Boolean} restOrigFrame
349      */
350     setRestoreOriginalFrame:function (restOrigFrame) {
351         this._restoreOriginalFrame = restOrigFrame;
352     },
353 
354     /**
355      * return whether or not it shall restore the original frame when the animation finishes
356      * @return {Boolean}
357      */
358     getRestoreOriginalFrame:function () {
359         return this._restoreOriginalFrame;
360     },
361 
362     /**
363      * return duration in seconds of the whole animation. It is the result of totalDelayUnits * delayPerUnit
364      * @return {Number}
365      */
366     getDuration:function () {
367         return this._totalDelayUnits * this._delayPerUnit;
368     },
369 
370     /**
371      * return Delay in seconds of the "delay unit"
372      * @return {Number}
373      */
374     getDelayPerUnit:function () {
375         return this._delayPerUnit;
376     },
377 
378     /**
379      * set Delay in seconds of the "delay unit"
380      * @param {Number} delayPerUnit
381      */
382     setDelayPerUnit:function (delayPerUnit) {
383         this._delayPerUnit = delayPerUnit;
384     },
385 
386     /**
387      * return total Delay units of the cc.Animation.
388      * @return {Number}
389      */
390     getTotalDelayUnits:function () {
391         return this._totalDelayUnits;
392     },
393 
394     /**
395      * Initializes a cc.Animation with frames and a delay between frames
396      * @param {Array} frames
397      * @param {Number} delay
398      * @param {Number} [loops=1]
399      */
400     initWithSpriteFrames:function (frames, delay, loops) {
401         cc.arrayVerifyType(frames, cc.SpriteFrame);
402         this._loops = loops === undefined ? 1 : loops;
403         this._delayPerUnit = delay || 0;
404         this._totalDelayUnits = 0;
405 
406         var locFrames = this._frames;
407         locFrames.length = 0;
408         if (frames) {
409             for (var i = 0; i < frames.length; i++) {
410                 var frame = frames[i];
411                 var animFrame = new cc.AnimationFrame();
412                 animFrame.initWithSpriteFrame(frame, 1, null);
413                 locFrames.push(animFrame);
414             }
415             this._totalDelayUnits += frames.length;
416         }
417         return true;
418     },
419     /**
420      * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB,
421      * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB.
422      * This is a hack, and should be removed once JSB fixes the retain/release bug
423      */
424     retain:function () {
425     },
426     release:function () {
427     }
428 });
429 
430 /**
431  * Creates an animation.
432  * @deprecated
433  * @param {Array} frames
434  * @param {Number} delay
435  * @param {Number} [loops=1]
436  * @return {cc.Animation}
437  * @example
438  * 1.
439  * //Creates an empty animation
440  * var animation1 = cc.Animation.create();
441  *
442  * 2.
443  * //Create an animation with sprite frames , delay and loops.
444  * var spriteFrames = [];
445  * var frame = cache.getSpriteFrame("grossini_dance_01.png");
446  * spriteFrames.push(frame);
447  * var animation1 = cc.Animation.create(spriteFrames);
448  * var animation2 = cc.Animation.create(spriteFrames, 0.2);
449  * var animation2 = cc.Animation.create(spriteFrames, 0.2, 2);
450  *
451  * 3.
452  * //Create an animation with animation frames , delay and loops.
453  * var animationFrames = [];
454  * var frame =  new cc.AnimationFrame();
455  * animationFrames.push(frame);
456  * var animation1 = cc.Animation.create(animationFrames);
457  * var animation2 = cc.Animation.create(animationFrames, 0.2);
458  * var animation3 = cc.Animation.create(animationFrames, 0.2, 2);
459  */
460 cc.Animation.create = function (frames, delay, loops) {
461     return new cc.Animation(frames, delay, loops);
462 };
463 
464 /**
465  * @deprecated
466  * @type {Function}
467  */
468 cc.Animation.createWithAnimationFrames = cc.Animation.create;