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