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