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  *     Singleton that manages the Animations.<br/>
 30  *     It saves in a cache the animations. You should use this class if you want to save your animations in a cache.<br/>
 31  * </p>
 32  * @class
 33  * @extends cc.Class
 34  *
 35  * @example
 36  * cc.AnimationCache.getInstance().addAnimation(animation,"animation1");
 37  */
 38 cc.AnimationCache = cc.Class.extend(/** @lends cc.AnimationCache# */{
 39 
 40     /**
 41      * Adds a cc.Animation with a name.
 42      * @param {cc.Animation} animation
 43      * @param {String} name
 44      */
 45     addAnimation:function (animation, name) {
 46         this._animations[name] = animation;
 47     },
 48 
 49     /**
 50      *  Deletes a cc.Animation from the cache.
 51      * @param  {String} name
 52      */
 53     removeAnimation:function (name) {
 54         if (!name) {
 55             return;
 56         }
 57         if (this._animations.hasOwnProperty(name)) {
 58             delete this._animations[name];
 59         }
 60     },
 61 
 62     /**
 63      * <p>
 64      *     Returns a cc.Animation that was previously added.<br/>
 65      *      If the name is not found it will return nil.<br/>
 66      *      You should retain the returned copy if you are going to use it.</br>
 67      * </p>
 68      * @param {String} name
 69      * @return {cc.Animation}
 70      */
 71     getAnimation:function (name) {
 72         if(this._animations.hasOwnProperty(name))
 73             return this._animations[name];
 74         return null;
 75     },
 76 
 77     /**
 78      * <p>
 79      *     Adds an animation from an NSDictionary<br/>
 80      *     Make sure that the frames were previously loaded in the cc.SpriteFrameCache.
 81      * </p>
 82      * @param {object} dictionary
 83      */
 84     addAnimationsWithDictionary:function (dictionary) {
 85         var animations = dictionary["animations"];
 86         if (!animations) {
 87             cc.log("cocos2d: cc.AnimationCache: No animations were found in provided dictionary.");
 88             return;
 89         }
 90 
 91         var version = 1;
 92         var properties = dictionary["properties"];
 93         if (properties) {
 94             version = (properties["format"] != null) ? parseInt(properties["format"]) : version;
 95             var spritesheets = properties["spritesheets"];
 96             for (var i = 0; i < spritesheets.length; i++) {
 97                 cc.SpriteFrameCache.getInstance().addSpriteFrames(spritesheets[i]);
 98             }
 99         }
100 
101         switch (version) {
102             case 1:
103                 this._parseVersion1(animations);
104                 break;
105             case 2:
106                 this._parseVersion2(animations);
107                 break;
108             default :
109                 cc.Assert(false, "Invalid animation format");
110                 break;
111         }
112     },
113 
114     /**
115      * <p>
116      *    Adds an animation from a plist file.<br/>
117      *    Make sure that the frames were previously loaded in the cc.SpriteFrameCache.
118      * </p>
119      * @param {String} plist
120      */
121     addAnimations:function (plist) {
122         cc.Assert(plist, "Invalid texture file name");
123 
124         var path = cc.FileUtils.getInstance().fullPathFromRelativePath(plist);
125         var dict = cc.FileUtils.getInstance().dictionaryWithContentsOfFileThreadSafe(path);
126 
127         cc.Assert(dict, "cc.AnimationCache: File could not be found");
128 
129         this.addAnimationsWithDictionary(dict);
130     },
131 
132     _parseVersion1:function (animations) {
133         var frameCache = cc.SpriteFrameCache.getInstance();
134 
135         for (var key in animations) {
136             var animationDict = animations[key];
137             var frameNames = animationDict["frames"];
138             var delay = parseFloat(animationDict["delay"]) || 0;
139             var animation = null;
140             if (!frameNames) {
141                 cc.log("cocos2d: cc.AnimationCache: Animation '" + key + "' found in dictionary without any frames - cannot add to animation cache.");
142                 continue;
143             }
144 
145             var frames = [];
146             for (var i = 0; i < frameNames.length; i++) {
147                 var spriteFrame = frameCache.getSpriteFrame(frameNames[i]);
148                 if (!spriteFrame) {
149                     cc.log("cocos2d: cc.AnimationCache: Animation '" + key + "' refers to frame '" + frameNames[i]
150                         + "' which is not currently in the cc.SpriteFrameCache. This frame will not be added to the animation.");
151                     continue;
152                 }
153                 var animFrame = new cc.AnimationFrame();
154                 animFrame.initWithSpriteFrame(spriteFrame, 1, null);
155                 frames.push(animFrame);
156             }
157 
158             if (frames.length === 0) {
159                 cc.log("cocos2d: cc.AnimationCache: None of the frames for animation '" + key
160                     + "' were found in the cc.SpriteFrameCache. Animation is not being added to the Animation Cache.");
161                 continue;
162             } else if (frames.length != frameNames.length) {
163                 cc.log("cocos2d: cc.AnimationCache: An animation in your dictionary refers to a frame which is not in the cc.SpriteFrameCache." +
164                     " Some or all of the frames for the animation '" + key + "' may be missing.");
165             }
166             animation = cc.Animation.createWithAnimationFrames(frames, delay, 1);
167             cc.AnimationCache.getInstance().addAnimation(animation, key);
168         }
169     },
170 
171     _parseVersion2:function (animations) {
172         var frameCache = cc.SpriteFrameCache.getInstance();
173 
174         for (var key in animations) {
175             var animationDict = animations[key];
176             var loops = parseInt(animationDict["loops"]) || 1;
177             var restoreOriginalFrame = (animationDict["restoreOriginalFrame"] && animationDict["restoreOriginalFrame"] == true) ? true : false;
178             var frameArray = animationDict["frames"];
179 
180             if (!frameArray) {
181                 cc.log("cocos2d: CCAnimationCache: Animation '" + key + "' found in dictionary without any frames - cannot add to animation cache.");
182                 continue;
183             }
184 
185             //Array of AnimationFrames
186             var arr = [];
187             for (var i = 0; i < frameArray.length; i++) {
188                 var entry = frameArray[i];
189                 var spriteFrameName = entry["spriteframe"];
190                 var spriteFrame = frameCache.getSpriteFrame(spriteFrameName);
191                 if (!spriteFrame) {
192                     cc.log("cocos2d: cc.AnimationCache: Animation '" + key + "' refers to frame '" + spriteFrameName
193                         + "' which is not currently in the cc.SpriteFrameCache. This frame will not be added to the animation.");
194                     continue;
195                 }
196 
197                 var delayUnits = parseFloat(entry["delayUnits"]) || 0;
198                 var userInfo = entry["notification"];
199                 var animFrame = new cc.AnimationFrame();
200                 animFrame.initWithSpriteFrame(spriteFrame, delayUnits, userInfo);
201                 arr.push(animFrame);
202             }
203 
204             var delayPerUnit = parseFloat(animationDict["delayPerUnit"]) || 0;
205             var animation = new cc.Animation();
206             animation.initWithAnimationFrames(arr, delayPerUnit, loops);
207             animation.setRestoreOriginalFrame(restoreOriginalFrame);
208             cc.AnimationCache.getInstance().addAnimation(animation, key);
209         }
210     },
211 
212     /**
213      * initialize cc.AnimationCache
214      * @return {Boolean}
215      */
216     init:function () {
217         this._animations = {};
218         return true;
219     },
220 
221     _animations:null
222 });
223 
224 /**
225  * Purges the cache. It releases all the cc.Animation objects and the shared instance.
226  */
227 cc.AnimationCache.purgeSharedAnimationCache = function () {
228     if (cc.s_sharedAnimationCache) {
229         cc.s_sharedAnimationCache._animations = null;
230         cc.s_sharedAnimationCache = null;
231     }
232 };
233 
234 /**
235  * Retruns ths shared instance of the Animation cache
236  * @return {cc.AnimationCache}
237  */
238 cc.AnimationCache.getInstance = function () {
239     if (cc.s_sharedAnimationCache === null) {
240         cc.s_sharedAnimationCache = new cc.AnimationCache();
241         cc.s_sharedAnimationCache.init();
242     }
243     return cc.s_sharedAnimationCache;
244 };
245 
246 cc.s_sharedAnimationCache = null;
247