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  * @namespace
 29  * <p>
 30  *     Singleton that manages the Animations.<br/>
 31  *     It saves in a cache the animations. You should use this class if you want to save your animations in a cache.<br/>
 32  * <br/>
 33  * example<br/>
 34  * cc.animationCache.addAnimation(animation,"animation1");<br/>
 35  * </p>
 36  */
 37 cc.animationCache = /** @lends cc.animationCache# */{
 38 	_animations: {},
 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[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[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      * @param {String} plist
 84      */
 85     _addAnimationsWithDictionary:function (dictionary,plist) {
 86         var animations = dictionary["animations"];
 87         if (!animations) {
 88             cc.log("cocos2d: cc.AnimationCache: No animations were found in provided dictionary.");
 89             return;
 90         }
 91 
 92         var version = 1;
 93         var properties = dictionary["properties"];
 94         if (properties) {
 95             version = (properties["format"] != null) ? parseInt(properties["format"]) : version;
 96             var spritesheets = properties["spritesheets"];
 97             var spriteFrameCache = cc.spriteFrameCache;
 98             var path = cc.path;
 99             for (var i = 0; i < spritesheets.length; i++) {
100                 spriteFrameCache.addSpriteFrames(path.changeBasename(plist, spritesheets[i]));
101             }
102         }
103 
104         switch (version) {
105             case 1:
106                 this._parseVersion1(animations);
107                 break;
108             case 2:
109                 this._parseVersion2(animations);
110                 break;
111             default :
112                 cc.log("cc.AnimationCache. Invalid animation format");
113                 break;
114         }
115     },
116 
117     /**
118      * <p>
119      *    Adds an animation from a plist file.<br/>
120      *    Make sure that the frames were previously loaded in the cc.SpriteFrameCache.
121      * </p>
122      * @param {String} plist
123      */
124     addAnimations:function (plist) {
125         if(!plist)
126             throw "cc.AnimationCache.addAnimations(): Invalid texture file name";
127         var dict = cc.loader.getRes(plist);
128 
129         if(!dict){
130             cc.log("cc.AnimationCache.addAnimations(): File could not be found");
131             return;
132         }
133 
134         this._addAnimationsWithDictionary(dict,plist);
135     },
136 
137     _parseVersion1:function (animations) {
138         var frameCache = cc.spriteFrameCache;
139 
140         for (var key in animations) {
141             var animationDict = animations[key];
142             var frameNames = animationDict["frames"];
143             var delay = parseFloat(animationDict["delay"]) || 0;
144             var animation = null;
145             if (!frameNames) {
146                 cc.log("cocos2d: cc.AnimationCache: Animation '" + key + "' found in dictionary without any frames - cannot add to animation cache.");
147                 continue;
148             }
149 
150             var frames = [];
151             for (var i = 0; i < frameNames.length; i++) {
152                 var spriteFrame = frameCache.getSpriteFrame(frameNames[i]);
153                 if (!spriteFrame) {
154                     cc.log("cocos2d: cc.AnimationCache: Animation '" + key + "' refers to frame '" + frameNames[i]
155                         + "' which is not currently in the cc.SpriteFrameCache. This frame will not be added to the animation.");
156                     continue;
157                 }
158                 var animFrame = new cc.AnimationFrame();
159                 animFrame.initWithSpriteFrame(spriteFrame, 1, null);
160                 frames.push(animFrame);
161             }
162 
163             if (frames.length === 0) {
164                 cc.log("cocos2d: cc.AnimationCache: None of the frames for animation '" + key
165                     + "' were found in the cc.SpriteFrameCache. Animation is not being added to the Animation Cache.");
166                 continue;
167             } else if (frames.length != frameNames.length) {
168                 cc.log("cocos2d: cc.AnimationCache: An animation in your dictionary refers to a frame which is not in the cc.SpriteFrameCache." +
169                     " Some or all of the frames for the animation '" + key + "' may be missing.");
170             }
171             animation = cc.Animation.create(frames, delay, 1);
172             cc.animationCache.addAnimation(animation, key);
173         }
174     },
175 
176     _parseVersion2:function (animations) {
177         var frameCache = cc.spriteFrameCache;
178 
179         for (var key in animations) {
180             var animationDict = animations[key];
181 
182             var isLoop = animationDict["loop"];
183             var loopsTemp = parseInt(animationDict["loops"]);
184             var loops = isLoop ? cc.REPEAT_FOREVER : ((isNaN(loopsTemp)) ? 1 : loopsTemp);
185             var restoreOriginalFrame = (animationDict["restoreOriginalFrame"] && animationDict["restoreOriginalFrame"] == true) ? true : false;
186             var frameArray = animationDict["frames"];
187 
188             if (!frameArray) {
189                 cc.log("cocos2d: CCAnimationCache: Animation '" + key + "' found in dictionary without any frames - cannot add to animation cache.");
190                 continue;
191             }
192 
193             //Array of AnimationFrames
194             var arr = [];
195             for (var i = 0; i < frameArray.length; i++) {
196                 var entry = frameArray[i];
197                 var spriteFrameName = entry["spriteframe"];
198                 var spriteFrame = frameCache.getSpriteFrame(spriteFrameName);
199                 if (!spriteFrame) {
200                     cc.log("cocos2d: cc.AnimationCache: Animation '" + key + "' refers to frame '" + spriteFrameName
201                         + "' which is not currently in the cc.SpriteFrameCache. This frame will not be added to the animation.");
202                     continue;
203                 }
204 
205                 var delayUnits = parseFloat(entry["delayUnits"]) || 0;
206                 var userInfo = entry["notification"];
207                 var animFrame = new cc.AnimationFrame();
208                 animFrame.initWithSpriteFrame(spriteFrame, delayUnits, userInfo);
209                 arr.push(animFrame);
210             }
211 
212             var delayPerUnit = parseFloat(animationDict["delayPerUnit"]) || 0;
213             var animation = new cc.Animation();
214             animation.initWithAnimationFrames(arr, delayPerUnit, loops);
215             animation.setRestoreOriginalFrame(restoreOriginalFrame);
216             cc.animationCache.addAnimation(animation, key);
217         }
218     },
219 
220 	_clear: function () {
221 		this._animations = {};
222 	}
223 };
224