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  * @param {cc.SpriteFrame} spriteFrame
138  * @param {Number} delayUnits
139  * @param {object} userInfo
140  * @example
141  *
142  */
143 cc.AnimationFrame.create = function(spriteFrame,delayUnits,userInfo){
144     return new cc.AnimationFrame(spriteFrame,delayUnits,userInfo);
145 };
146 
147 /**
148  * <p>
149  *     A cc.Animation object is used to perform animations on the cc.Sprite objects.<br/>
150  *     <br/>
151  *      The cc.Animation object contains cc.SpriteFrame objects, and a possible delay between the frames. <br/>
152  *      You can animate a cc.Animation object by using the cc.Animate action. Example:  <br/>
153  * </p>
154  * @class
155  * @extends cc.Class
156  *
157  * @example
158  * //create an animation object
159  * var animation = cc.Animation.create();
160  *
161  * //add a sprite frame to this animation
162  * animation.addFrameWithFile("grossini_dance_01.png");
163  *
164  * //create an animate with this animation
165  * var action = cc.Animate.create(animation);
166  *
167  * //run animate
168  * this._grossini.runAction(action);
169  */
170 cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{
171     _frames:null,
172     _loops:0,
173     _restoreOriginalFrame:false,
174     _duration:0,
175     _delayPerUnit:0,
176     _totalDelayUnits:0,
177 
178 	/**
179 	 * Creates an animation.
180 	 * Constructor of cc.Animation
181 	 * @param {Array} frames
182 	 * @param {Number} delay
183 	 * @param {Number} [loops=1]
184 	 * @example
185 	 * // 1. Creates an empty animation
186 	 * var animation1 = new cc.Animation();
187 	 *
188 	 * // 2. Create an animation with sprite frames, delay and loops.
189 	 * var spriteFrames = [];
190 	 * var frame = cache.getSpriteFrame("grossini_dance_01.png");
191 	 * spriteFrames.push(frame);
192 	 * var animation1 = new cc.Animation(spriteFrames);
193 	 * var animation2 = new cc.Animation(spriteFrames, 0.2);
194 	 * var animation2 = new cc.Animation(spriteFrames, 0.2, 2);
195 	 *
196 	 * // 3. Create an animation with animation frames, delay and loops.
197 	 * var animationFrames = [];
198 	 * var frame =  new cc.AnimationFrame();
199 	 * animationFrames.push(frame);
200 	 * var animation1 = new cc.Animation(animationFrames);
201 	 * var animation2 = new cc.Animation(animationFrames, 0.2);
202 	 * var animation3 = new cc.Animation(animationFrames, 0.2, 2);
203 	 */
204     ctor:function (frames, delay, loops) {
205         this._frames = [];
206 
207 		if (frames === undefined) {
208 			this.initWithSpriteFrames(null, 0);
209 		} else {
210 			var frame0 = frames[0];
211 			if(frame0){
212 				if (frame0 instanceof cc.SpriteFrame) {
213 					//init with sprite frames , delay and loops.
214 					this.initWithSpriteFrames(frames, delay, loops);
215 				}else if(frame0 instanceof cc.AnimationFrame) {
216 					//init with sprite frames , delay and loops.
217 					this.initWithAnimationFrames(frames, delay, loops);
218 				}
219 			}
220 		}
221     },
222 
223     // attributes
224 
225     /**
226      * return array of CCAnimationFrames
227      * @return {Array}
228      */
229     getFrames:function () {
230         return this._frames;
231     },
232 
233     /**
234      * array of CCAnimationFrames setter
235      * @param {Array} frames
236      */
237     setFrames:function (frames) {
238         this._frames = frames;
239     },
240 
241     /**
242      * adds a frame to a cc.Animation  The frame will be added with one "delay unit".
243      * @param {cc.SpriteFrame} frame
244      */
245     addSpriteFrame:function (frame) {
246         var animFrame = new cc.AnimationFrame();
247 
248         animFrame.initWithSpriteFrame(frame, 1, null);
249         this._frames.push(animFrame);
250         // update duration
251         this._totalDelayUnits++;
252     },
253 
254     /**
255      * 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".
256      * @param {String} fileName
257      */
258     addSpriteFrameWithFile:function (fileName) {
259         var texture = cc.textureCache.addImage(fileName);
260         var rect = cc.rect(0, 0, 0, 0);
261         rect.width = texture.width;
262         rect.height = texture.height;
263         var frame = cc.SpriteFrame.create(texture, rect);
264         this.addSpriteFrame(frame);
265     },
266 
267     /**
268      * 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".
269      * @param {cc.Texture2D} texture
270      * @param {cc.Rect} rect
271      */
272     addSpriteFrameWithTexture:function (texture, rect) {
273         var pFrame = cc.SpriteFrame.create(texture, rect);
274         this.addSpriteFrame(pFrame);
275     },
276 
277     /**
278      * Initializes a cc.Animation with cc.AnimationFrame
279      * @param {Array} arrayOfAnimationFrames
280      * @param {Number} delayPerUnit
281      * @param {Number} [loops=1]
282      */
283     initWithAnimationFrames:function (arrayOfAnimationFrames, delayPerUnit, loops) {
284         cc.arrayVerifyType(arrayOfAnimationFrames, cc.AnimationFrame);
285 
286         this._delayPerUnit = delayPerUnit;
287         this._loops = loops === undefined ? 1 : loops;
288         this._totalDelayUnits = 0;
289 
290         var locFrames = this._frames;
291         locFrames.length = 0;
292         for (var i = 0; i < arrayOfAnimationFrames.length; i++) {
293             var animFrame = arrayOfAnimationFrames[i];
294             locFrames.push(animFrame);
295             this._totalDelayUnits += animFrame.getDelayUnits();
296         }
297 
298         return true;
299     },
300 
301     clone: function(){
302         var animation = new cc.Animation();
303         animation.initWithAnimationFrames(this._copyFrames(), this._delayPerUnit, this._loops);
304         animation.setRestoreOriginalFrame(this._restoreOriginalFrame);
305         return animation;
306     },
307 
308     /**
309      * @param {cc.Animation} pZone
310      */
311     copyWithZone:function (pZone) {
312         var pCopy = new cc.Animation();
313         pCopy.initWithAnimationFrames(this._copyFrames(), this._delayPerUnit, this._loops);
314         pCopy.setRestoreOriginalFrame(this._restoreOriginalFrame);
315         return pCopy;
316     },
317 
318     _copyFrames:function(){
319        var copyFrames = [];
320         for(var i = 0; i< this._frames.length;i++)
321             copyFrames.push(this._frames[i].clone());
322         return copyFrames;
323     },
324 
325     copy:function (pZone) {
326         return this.copyWithZone(null);
327     },
328 
329     /**
330      * return how many times the animation is going to loop. 0 means animation is not animated. 1, animation is executed one time, ...
331      * @return {Number}
332      */
333     getLoops:function () {
334         return this._loops;
335     },
336 
337     /**
338      * set how many times the animation is going to loop. 0 means animation is not animated. 1, animation is executed one time, ...
339      * @param {Number} value
340      */
341     setLoops:function (value) {
342         this._loops = value;
343     },
344 
345     /**
346      * whether or not it shall restore the original frame when the animation finishes
347      * @param {Boolean} restOrigFrame
348      */
349     setRestoreOriginalFrame:function (restOrigFrame) {
350         this._restoreOriginalFrame = restOrigFrame;
351     },
352 
353     /**
354      * return whether or not it shall restore the original frame when the animation finishes
355      * @return {Boolean}
356      */
357     getRestoreOriginalFrame:function () {
358         return this._restoreOriginalFrame;
359     },
360 
361     /**
362      * return duration in seconds of the whole animation. It is the result of totalDelayUnits * delayPerUnit
363      * @return {Number}
364      */
365     getDuration:function () {
366         return this._totalDelayUnits * this._delayPerUnit;
367     },
368 
369     /**
370      * return Delay in seconds of the "delay unit"
371      * @return {Number}
372      */
373     getDelayPerUnit:function () {
374         return this._delayPerUnit;
375     },
376 
377     /**
378      * set Delay in seconds of the "delay unit"
379      * @param {Number} delayPerUnit
380      */
381     setDelayPerUnit:function (delayPerUnit) {
382         this._delayPerUnit = delayPerUnit;
383     },
384 
385     /**
386      * return total Delay units of the cc.Animation.
387      * @return {Number}
388      */
389     getTotalDelayUnits:function () {
390         return this._totalDelayUnits;
391     },
392 
393     /**
394      * Initializes a cc.Animation with frames and a delay between frames
395      * @param {Array} frames
396      * @param {Number} delay
397      * @param {Number} [loops=1]
398      */
399     initWithSpriteFrames:function (frames, delay, loops) {
400         cc.arrayVerifyType(frames, cc.SpriteFrame);
401         this._loops = loops === undefined ? 1 : loops;
402         this._delayPerUnit = delay || 0;
403         this._totalDelayUnits = 0;
404 
405         var locFrames = this._frames;
406         locFrames.length = 0;
407         if (frames) {
408             for (var i = 0; i < frames.length; i++) {
409                 var frame = frames[i];
410                 var animFrame = new cc.AnimationFrame();
411                 animFrame.initWithSpriteFrame(frame, 1, null);
412                 locFrames.push(animFrame);
413             }
414             this._totalDelayUnits += frames.length;
415         }
416         return true;
417     },
418     /**
419      * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB,
420      * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB.
421      * This is a hack, and should be removed once JSB fixes the retain/release bug
422      */
423     retain:function () {
424     },
425     release:function () {
426     }
427 });
428 
429 /**
430  * Creates an animation.
431  * @param {Array} frames
432  * @param {Number} delay
433  * @param {Number} [loops=1]
434  * @return {cc.Animation}
435  * @example
436  * 1.
437  * //Creates an empty animation
438  * var animation1 = cc.Animation.create();
439  *
440  * 2.
441  * //Create an animation with sprite frames , delay and loops.
442  * var spriteFrames = [];
443  * var frame = cache.getSpriteFrame("grossini_dance_01.png");
444  * spriteFrames.push(frame);
445  * var animation1 = cc.Animation.create(spriteFrames);
446  * var animation2 = cc.Animation.create(spriteFrames, 0.2);
447  * var animation2 = cc.Animation.create(spriteFrames, 0.2, 2);
448  *
449  * 3.
450  * //Create an animation with animation frames , delay and loops.
451  * var animationFrames = [];
452  * var frame =  new cc.AnimationFrame();
453  * animationFrames.push(frame);
454  * var animation1 = cc.Animation.create(animationFrames);
455  * var animation2 = cc.Animation.create(animationFrames, 0.2);
456  * var animation3 = cc.Animation.create(animationFrames, 0.2, 2);
457  */
458 cc.Animation.create = function (frames, delay, loops) {
459     return new cc.Animation(frames, delay, loops);
460 };
461