1 /**************************************************************************** 2 Copyright (c) 2011-2012 cocos2d-x.org 3 Copyright (c) 2013-2014 Chukong Technologies Inc. 4 Copyright (c) 2014 Shengxiang Chen (Nero Chan) 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 * @ignore 29 */ 30 sp._atlasPage_createTexture_webGL = function (self, path) { 31 var texture = cc.textureCache.addImage(path); 32 self.rendererObject = new cc.TextureAtlas(texture, 128); 33 self.width = texture.getPixelsWide(); 34 self.height = texture.getPixelsHigh(); 35 }; 36 37 sp._atlasPage_createTexture_canvas = function(self, path) { 38 self._texture = cc.textureCache.addImage(path); 39 }; 40 41 sp._atlasPage_disposeTexture = function (self) { 42 self.rendererObject.release(); 43 }; 44 45 sp._atlasLoader = { 46 spAtlasFile:null, 47 setAtlasFile:function(spAtlasFile){ 48 this.spAtlasFile = spAtlasFile; 49 }, 50 load:function(page, line, spAtlas){ 51 var texturePath = cc.path.join(cc.path.dirname(this.spAtlasFile), line); 52 if (cc._renderType === cc._RENDER_TYPE_WEBGL) 53 sp._atlasPage_createTexture_webGL(page,texturePath); 54 else 55 sp._atlasPage_createTexture_canvas(page,texturePath); 56 }, 57 unload:function(obj){ 58 } 59 }; 60 61 /** 62 * The event type of spine skeleton animation. It contains event types: START(0), END(1), COMPLETE(2), EVENT(3). 63 * @constant 64 * @type {{START: number, END: number, COMPLETE: number, EVENT: number}} 65 */ 66 sp.ANIMATION_EVENT_TYPE = { 67 START: 0, 68 END: 1, 69 COMPLETE: 2, 70 EVENT: 3 71 }; 72 73 sp.TrackEntryListeners = function(startListener, endListener, completeListener, eventListener){ 74 this.startListener = startListener || null; 75 this.endListener = endListener || null; 76 this.completeListener = completeListener || null; 77 this.eventListener = eventListener || null; 78 }; 79 80 sp.TrackEntryListeners.getListeners = function(entry){ 81 if(!entry.rendererObject){ 82 entry.rendererObject = new sp.TrackEntryListeners(); 83 entry.listener = sp.trackEntryCallback; 84 } 85 return entry.rendererObject; 86 }; 87 88 sp.trackEntryCallback = function(state, trackIndex, type, event, loopCount) { 89 state.rendererObject.onTrackEntryEvent(trackIndex, type, event, loopCount); 90 }; 91 92 /** 93 * The skeleton animation of spine. It updates animation's state and skeleton's world transform. 94 * @class 95 * @extends sp.Skeleton 96 * @example 97 * var spineBoy = new sp.SkeletonAnimation('res/skeletons/spineboy.json', 'res/skeletons/spineboy.atlas'); 98 * this.addChild(spineBoy, 4); 99 */ 100 sp.SkeletonAnimation = sp.Skeleton.extend(/** @lends sp.SkeletonAnimation# */{ 101 _state: null, 102 _target: null, 103 _callback: null, 104 105 _ownsAnimationStateData: false, 106 _startListener: null, 107 _endListener: null, 108 _completeListener: null, 109 _eventListener: null, 110 111 /** 112 * Initializes a sp.SkeletonAnimation. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. 113 * @override 114 */ 115 init: function () { 116 sp.Skeleton.prototype.init.call(this); 117 this._ownsAnimationStateData = true; 118 this.setAnimationStateData(new spine.AnimationStateData(this._skeleton.data)); 119 }, 120 121 /** 122 * Sets animation state data to sp.SkeletonAnimation. 123 * @param {spine.AnimationStateData} stateData 124 */ 125 setAnimationStateData: function (stateData) { 126 var state = new spine.AnimationState(stateData); 127 state.rendererObject = this; 128 state.onStart = this._onAnimationStateStart.bind(this); 129 state.onComplete = this._onAnimationStateComplete.bind(this); 130 state.onEnd = this._onAnimationStateEnd.bind(this); 131 state.onEvent = this._onAnimationStateEvent.bind(this); 132 this._state = state; 133 }, 134 135 /** 136 * Mix applies all keyframe values, interpolated for the specified time and mixed with the current values. <br/> 137 * @param {String} fromAnimation 138 * @param {String} toAnimation 139 * @param {Number} duration 140 */ 141 setMix: function (fromAnimation, toAnimation, duration) { 142 this._state.data.setMixByName(fromAnimation, toAnimation, duration); 143 }, 144 145 /** 146 * Sets event listener of sp.SkeletonAnimation. 147 * @param {Object} target 148 * @param {Function} callback 149 */ 150 setAnimationListener: function (target, callback) { 151 this._target = target; 152 this._callback = callback; 153 }, 154 155 /** 156 * Set the current animation. Any queued animations are cleared. 157 * @param {Number} trackIndex 158 * @param {String} name 159 * @param {Boolean} loop 160 * @returns {spine.TrackEntry|null} 161 */ 162 setAnimation: function (trackIndex, name, loop) { 163 var animation = this._skeleton.data.findAnimation(name); 164 if (!animation) { 165 cc.log("Spine: Animation not found: " + name); 166 return null; 167 } 168 return this._state.setAnimation(trackIndex, animation, loop); 169 }, 170 171 /** 172 * Adds an animation to be played delay seconds after the current or last queued animation. 173 * @param {Number} trackIndex 174 * @param {String} name 175 * @param {Boolean} loop 176 * @param {Number} [delay=0] 177 * @returns {spine.TrackEntry|null} 178 */ 179 addAnimation: function (trackIndex, name, loop, delay) { 180 delay = delay == null ? 0 : delay; 181 var animation = this._skeleton.data.findAnimation(name); 182 if (!animation) { 183 cc.log("Spine: Animation not found:" + name); 184 return null; 185 } 186 return this._state.addAnimation(trackIndex, animation, loop, delay); 187 }, 188 189 /** 190 * Returns track entry by trackIndex. 191 * @param trackIndex 192 * @returns {spine.TrackEntry|null} 193 */ 194 getCurrent: function (trackIndex) { 195 return this._state.getCurrent(trackIndex); 196 }, 197 198 /** 199 * Clears all tracks of animation state. 200 */ 201 clearTracks: function () { 202 this._state.clearTracks(); 203 }, 204 205 /** 206 * Clears track of animation state by trackIndex. 207 * @param {Number} trackIndex 208 */ 209 clearTrack: function (trackIndex) { 210 this._state.clearTrack(trackIndex); 211 }, 212 213 /** 214 * Update will be called automatically every frame if "scheduleUpdate" is called when the node is "live". 215 * It updates animation's state and skeleton's world transform. 216 * @param {Number} dt Delta time since last update 217 * @override 218 */ 219 update: function (dt) { 220 this._super(dt); 221 dt *= this._timeScale; 222 this._state.update(dt); 223 this._state.apply(this._skeleton); 224 this._skeleton.updateWorldTransform(); 225 this._renderCmd._updateChild(); 226 }, 227 228 /** 229 * Set the start event listener. 230 * @param {function} listener 231 */ 232 setStartListener: function(listener){ 233 this._startListener = listener; 234 }, 235 236 /** 237 * Set the end event listener. 238 * @param {function} listener 239 */ 240 setEndListener: function(listener) { 241 this._endListener = listener; 242 }, 243 244 setCompleteListener: function(listener) { 245 this._completeListener = listener; 246 }, 247 248 setEventListener: function(listener){ 249 this._eventListener = listener; 250 }, 251 252 setTrackStartListener: function(entry, listener){ 253 sp.TrackEntryListeners.getListeners(entry).startListener = listener; 254 }, 255 256 setTrackEndListener: function(entry, listener){ 257 sp.TrackEntryListeners.getListeners(entry).endListener = listener; 258 }, 259 260 setTrackCompleteListener: function(entry, listener){ 261 sp.TrackEntryListeners.getListeners(entry).completeListener = listener; 262 }, 263 264 setTrackEventListener: function(entry, listener){ 265 sp.TrackEntryListeners.getListeners(entry).eventListener = listener; 266 }, 267 268 onTrackEntryEvent: function(traceIndex, type, event, loopCount){ 269 var entry = this._state.getCurrent(traceIndex); 270 if(!entry.rendererObject) 271 return; 272 var listeners = entry.rendererObject; 273 switch (type){ 274 case sp.ANIMATION_EVENT_TYPE.START: 275 if(listeners.startListener) 276 listeners.startListener(traceIndex); 277 break; 278 case sp.ANIMATION_EVENT_TYPE.END: 279 if(listeners.endListener) 280 listeners.endListener(traceIndex); 281 break; 282 case sp.ANIMATION_EVENT_TYPE.COMPLETE: 283 if(listeners.completeListener) 284 listeners.completeListener(traceIndex, loopCount); 285 break; 286 case sp.ANIMATION_EVENT_TYPE.EVENT: 287 if(listeners.eventListener) 288 listeners.eventListener(traceIndex, event); 289 break; 290 } 291 }, 292 293 onAnimationStateEvent: function(trackIndex, type, event, loopCount) { 294 switch(type){ 295 case sp.ANIMATION_EVENT_TYPE.START: 296 if(this._startListener) 297 this._startListener(trackIndex); 298 break; 299 case sp.ANIMATION_EVENT_TYPE.END: 300 if(this._endListener) 301 this._endListener(trackIndex); 302 break; 303 case sp.ANIMATION_EVENT_TYPE.COMPLETE: 304 if(this._completeListener) 305 this._completeListener(trackIndex, loopCount); 306 break; 307 case sp.ANIMATION_EVENT_TYPE.EVENT: 308 if(this._eventListener) 309 this._eventListener(trackIndex, event); 310 break; 311 } 312 }, 313 314 getState: function(){ 315 return this._state; 316 }, 317 318 _onAnimationStateStart: function (trackIndex) { 319 this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.START, null, 0); 320 }, 321 _onAnimationStateEnd: function (trackIndex) { 322 this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.END, null, 0); 323 }, 324 _onAnimationStateComplete: function (trackIndex, count) { 325 this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.COMPLETE, null, count); 326 }, 327 _onAnimationStateEvent: function (trackIndex, event) { 328 this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.EVENT, event, 0); 329 }, 330 _animationStateCallback: function (trackIndex, type, event, loopCount) { 331 this.onAnimationStateEvent(trackIndex, type, event, loopCount); 332 if (this._target && this._callback) { 333 this._callback.call(this._target, this, trackIndex, type, event, loopCount) 334 } 335 } 336 }); 337 338 /** 339 * Creates a skeleton animation object. 340 * @deprecated since v3.0, please use new sp.SkeletonAnimation(skeletonDataFile, atlasFile, scale) instead. 341 * @param {spine.SkeletonData|String} skeletonDataFile 342 * @param {String|spine.Atlas|spine.SkeletonData} atlasFile atlas filename or atlas data or owns SkeletonData 343 * @param {Number} [scale] scale can be specified on the JSON or binary loader which will scale the bone positions, image sizes, and animation translations. 344 * @returns {sp.Skeleton} 345 */ 346 sp.SkeletonAnimation.create = function (skeletonDataFile, atlasFile/* or atlas*/, scale) { 347 return new sp.SkeletonAnimation(skeletonDataFile, atlasFile, scale); 348 };