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