1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 4 http://www.cocos2d-x.org 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 ****************************************************************************/ 24 25 /** 26 * movement event type 27 * @type {Object} 28 */ 29 ccs.MovementEventType = { 30 start: 0, 31 complete: 1, 32 loopComplete: 2 33 }; 34 /** 35 * Base class for cc.MovementEvent objects. 36 * @class 37 * @extends ccs.Class 38 */ 39 ccs.AnimationEvent = ccs.Class.extend({ 40 _arguments:null, 41 _callFunc:null, 42 _selectorTarget:null, 43 ctor:function (target, callFunc, data) { 44 this._data = data; 45 this._callFunc = callFunc; 46 this._selectorTarget = target; 47 }, 48 call:function () { 49 if (this._callFunc) { 50 this._callFunc.apply(this._selectorTarget, this._arguments); 51 } 52 }, 53 setArguments:function (args) { 54 this._arguments = args; 55 } 56 }); 57 /** 58 * frame event 59 * @constructor 60 */ 61 ccs.FrameEvent = function () { 62 this.bone = null; 63 this.frameEventName = ""; 64 this.originFrameIndex = 0; 65 this.currentFrameIndex = 0; 66 }; 67 /** 68 * Base class for ccs.ArmatureAnimation objects. 69 * @class 70 * @extends ccs.ProcessBase 71 */ 72 ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# */{ 73 _animationData:null, 74 _movementData:null, 75 _armature:null, 76 _movementID:"", 77 _prevFrameIndex:0, 78 _toIndex:0, 79 _tweenList:null, 80 _frameEvent:null, 81 _movementEvent:null, 82 _speedScale:1, 83 _ignoreFrameEvent:false, 84 _frameEventQueue:[], 85 _userObject:null, 86 ctor:function () { 87 ccs.ProcessBase.prototype.ctor.call(this); 88 this._animationData = null; 89 this._movementData = null; 90 this._movementID = ""; 91 this._armature = null; 92 this._prevFrameIndex = 0; 93 this._toIndex = 0; 94 this._tweenList = []; 95 this._frameEvent = null; 96 this._movementEvent = null; 97 this._speedScale = 1; 98 this._ignoreFrameEvent = false; 99 this._frameEventQueue = []; 100 this._userObject = null; 101 }, 102 103 /** 104 * init with a CCArmature 105 * @param {ccs.Armature} armature 106 * @return {Boolean} 107 */ 108 init:function (armature) { 109 this._armature = armature; 110 this._tweenList = []; 111 return true; 112 }, 113 pause:function () { 114 for (var i = 0; i < this._tweenList.length; i++) { 115 this._tweenList[i].pause(); 116 } 117 ccs.ProcessBase.prototype.pause.call(this); 118 }, 119 resume:function () { 120 for (var i = 0; i < this._tweenList.length; i++) { 121 this._tweenList[i].resume(); 122 } 123 ccs.ProcessBase.prototype.resume.call(this); 124 }, 125 126 stop:function () { 127 for (var i = 0; i < this._tweenList.length; i++) { 128 this._tweenList[i].stop(); 129 } 130 this._tweenList = []; 131 ccs.ProcessBase.prototype.stop.call(this); 132 }, 133 134 /** 135 * scale animation play speed 136 * @param {Number} speedScale 137 */ 138 setSpeedScale:function (speedScale) { 139 if (speedScale == this._speedScale) { 140 return; 141 } 142 this._speedScale = speedScale; 143 this._processScale = !this._movementData ? this._speedScale : this._speedScale * this._movementData.scale; 144 var dict = this._armature.getBoneDic(); 145 for (var key in dict) { 146 var bone = dict[key]; 147 bone.getTween().setProcessScale(this._processScale); 148 if (bone.getChildArmature()) { 149 bone.getChildArmature().getAnimation().setProcessScale(this._processScale); 150 } 151 } 152 }, 153 154 getSpeedScale:function(){ 155 return this._speedScale; 156 }, 157 158 getAnimationScale:function(){ 159 return this.getSpeedScale(); 160 }, 161 setAnimationScale:function(animationScale){ 162 return this.setSpeedScale(animationScale); 163 }, 164 165 setAnimationInternal:function (animationInternal) { 166 if (animationInternal == this._animationInternal) { 167 return; 168 } 169 this._animationInternal = animationInternal; 170 171 var dict = this._armature.getBoneDic(); 172 for (var key in dict) { 173 var bone = dict[key]; 174 bone.getTween().setAnimationInternal(this._animationInternal); 175 if (bone.getChildArmature()) { 176 bone.getChildArmature().getAnimation().setAnimationInternal(this._animationInternal); 177 } 178 } 179 }, 180 181 /** 182 * play animation by animation name. 183 * @param {Number} animationName The animation name you want to play 184 * @param {Number} durationTo 185 * he frames between two animation changing-over.It's meaning is changing to this animation need how many frames 186 * -1 : use the value from CCMovementData get from flash design panel 187 * @param {Number} durationTween he 188 * frame count you want to play in the game.if _durationTween is 80, then the animation will played 80 frames in a loop 189 * -1 : use the value from CCMovementData get from flash design panel 190 * @param {Number} loop 191 * Whether the animation is loop. 192 * loop < 0 : use the value from CCMovementData get from flash design panel 193 * loop = 0 : this animation is not loop 194 * loop > 0 : this animation is loop 195 * @param {Number} tweenEasing 196 * CCTween easing is used for calculate easing effect 197 * TWEEN_EASING_MAX : use the value from CCMovementData get from flash design panel 198 * -1 : fade out 199 * 0 : line 200 * 1 : fade in 201 * 2 : fade in and out 202 */ 203 play:function (animationName, durationTo, durationTween, loop, tweenEasing) { 204 if (this._animationData == null) { 205 cc.log("this._animationData can not be null"); 206 return; 207 } 208 this._movementData = this._animationData.getMovement(animationName); 209 if (this._movementData == null) { 210 cc.log("this._movementData can not be null"); 211 return; 212 } 213 if (typeof durationTo == "undefined") { 214 durationTo = -1; 215 } 216 if (typeof durationTween == "undefined") { 217 durationTween = -1; 218 } 219 if (typeof loop == "undefined") { 220 loop = -1; 221 } 222 if (typeof tweenEasing == "undefined") { 223 tweenEasing = ccs.TweenType.tweenEasingMax; 224 } 225 var locMovementData = this._movementData; 226 //Get key frame count 227 this._rawDuration = locMovementData.duration; 228 this._movementID = animationName; 229 this._processScale = this._speedScale * locMovementData.scale; 230 //Further processing parameters 231 durationTo = (durationTo == -1) ? locMovementData.durationTo : durationTo; 232 durationTween = (durationTween == -1) ? locMovementData.durationTween : durationTween; 233 durationTween = (durationTween == 0) ? locMovementData.duration : durationTween;//todo 234 tweenEasing = (tweenEasing == ccs.TweenType.tweenEasingMax) ? locMovementData.tweenEasing : tweenEasing; 235 loop = (loop < 0) ? locMovementData.loop : loop; 236 237 ccs.ProcessBase.prototype.play.call(this, durationTo, durationTween, loop, tweenEasing); 238 239 if (this._rawDuration == 0) { 240 this._loopType = CC_ANIMATION_TYPE_SINGLE_FRAME; 241 } 242 else { 243 if (loop) { 244 this._loopType = CC_ANIMATION_TYPE_TO_LOOP_FRONT; 245 } 246 else { 247 this._loopType = CC_ANIMATION_TYPE_NO_LOOP; 248 this._rawDuration--; 249 } 250 this._durationTween = durationTween; 251 } 252 253 this._tweenList = []; 254 255 var movementBoneData; 256 var dict = this._armature.getBoneDic(); 257 for (var key in dict) { 258 var bone = dict[key]; 259 movementBoneData = locMovementData.getMovementBoneData(bone.getName()); 260 var tween = bone.getTween(); 261 if (movementBoneData && movementBoneData.frameList.length > 0) { 262 this._tweenList.push(tween); 263 movementBoneData.duration = locMovementData.duration; 264 tween.play(movementBoneData, durationTo, durationTween, loop, tweenEasing); 265 266 tween.setProcessScale(this._processScale); 267 tween.setAnimationInternal(this._animationInternal); 268 if (bone.getChildArmature()) { 269 bone.getChildArmature().getAnimation().setProcessScale(this._processScale); 270 bone.getChildArmature().getAnimation().setAnimationInternal(this._animationInternal); 271 } 272 } else { 273 if (!bone.getIgnoreMovementBoneData()) { 274 bone.getDisplayManager().changeDisplayByIndex(-1, false); 275 tween.stop(); 276 } 277 } 278 } 279 this._armature.update(0); 280 }, 281 282 /** 283 * Go to specified frame and play current movement. 284 * You need first switch to the movement you want to play, then call this function. 285 * 286 * example : playByIndex(0); 287 * gotoAndPlay(0); 288 * playByIndex(1); 289 * gotoAndPlay(0); 290 * gotoAndPlay(15); 291 * @param {Number} frameIndex 292 */ 293 gotoAndPlay: function (frameIndex) { 294 if (!this._movementData || frameIndex < 0 || frameIndex >= this._movementData.duration) { 295 cc.log("Please ensure you have played a movement, and the frameIndex is in the range."); 296 return; 297 } 298 299 var ignoreFrameEvent = this._ignoreFrameEvent; 300 this._ignoreFrameEvent = true; 301 this._isPlaying = true; 302 this._isComplete = this._isPause = false; 303 304 ccs.ProcessBase.prototype.gotoFrame.call(this, frameIndex); 305 this._currentPercent = this._curFrameIndex / this._movementData.duration; 306 this._currentFrame = this._nextFrameIndex * this._currentPercent; 307 308 for (var i = 0; i < this._tweenList.length; i++) { 309 var tween = this._tweenList[i]; 310 tween.gotoAndPlay(frameIndex); 311 } 312 this._armature.update(0); 313 this._ignoreFrameEvent = ignoreFrameEvent; 314 }, 315 316 /** 317 * Go to specified frame and pause current movement. 318 * @param {Number} frameIndex 319 */ 320 gotoAndPause: function (frameIndex) { 321 this.gotoAndPlay(frameIndex); 322 this.pause(); 323 }, 324 325 /** 326 * Play animation by index, the other param is the same to play. 327 * @param {Number} animationIndex 328 * @param {Number} durationTo 329 * @param {Number} durationTween 330 * @param {Number} loop 331 * @param {Number} tweenEasing 332 */ 333 playByIndex:function (animationIndex, durationTo, durationTween, loop, tweenEasing) { 334 if (typeof durationTo == "undefined") { 335 durationTo = -1; 336 } 337 if (typeof durationTween == "undefined") { 338 durationTween = -1; 339 } 340 if (typeof loop == "undefined") { 341 loop = -1; 342 } 343 if (typeof tweenEasing == "undefined") { 344 tweenEasing = 10000; 345 } 346 var moveNames = this._animationData.movementNames; 347 if (animationIndex < -1 || animationIndex >= moveNames.length) { 348 return; 349 } 350 var animationName = moveNames[animationIndex]; 351 this.play(animationName, durationTo, durationTween, loop, tweenEasing); 352 }, 353 354 /** 355 * get movement count 356 * @return {Number} 357 */ 358 getMovementCount:function () { 359 return this._animationData.getMovementCount(); 360 }, 361 362 update:function (dt) { 363 if(ccs.ProcessBase.prototype.update.call(this, dt)){ 364 for (var i = 0; i < this._tweenList.length; i++) { 365 this._tweenList[i].update(dt); 366 } 367 } 368 if (this._frameEventQueue.length > 0) { 369 for (var i = 0; i < this._frameEventQueue.length; i++) { 370 var frameEvent = this._frameEventQueue[i]; 371 this._ignoreFrameEvent = true; 372 this.callFrameEvent([frameEvent.bone, frameEvent.frameEventName, frameEvent.originFrameIndex, frameEvent.currentFrameIndex]); 373 this._ignoreFrameEvent = false; 374 } 375 this._frameEventQueue = []; 376 } 377 }, 378 379 /** 380 * update will call this handler, you can handle your logic here 381 */ 382 updateHandler:function () { 383 var locCurrentPercent = this._currentPercent; 384 if (locCurrentPercent >= 1) { 385 switch (this._loopType) { 386 case CC_ANIMATION_TYPE_NO_LOOP: 387 this._loopType = CC_ANIMATION_TYPE_MAX; 388 this._currentFrame = (locCurrentPercent - 1) * this._nextFrameIndex; 389 locCurrentPercent = this._currentFrame / this._durationTween; 390 if (locCurrentPercent < 1.0) { 391 this._nextFrameIndex = this._durationTween; 392 this.callMovementEvent([this._armature, ccs.MovementEventType.start, this._movementID]); 393 break; 394 } 395 case CC_ANIMATION_TYPE_MAX: 396 case CC_ANIMATION_TYPE_SINGLE_FRAME: 397 locCurrentPercent = 1; 398 this._isComplete = true; 399 this._isPlaying = false; 400 this.callMovementEvent([this._armature, ccs.MovementEventType.complete, this._movementID]); 401 break; 402 case CC_ANIMATION_TYPE_TO_LOOP_FRONT: 403 this._loopType = CC_ANIMATION_TYPE_LOOP_FRONT; 404 locCurrentPercent = ccs.fmodf(locCurrentPercent, 1); 405 this._currentFrame = this._nextFrameIndex == 0 ? 0 : ccs.fmodf(this._currentFrame, this._nextFrameIndex); 406 this._nextFrameIndex = this._durationTween > 0 ? this._durationTween : 1; 407 this.callMovementEvent([this, ccs.MovementEventType.start, this._movementID]); 408 break; 409 default: 410 //locCurrentPercent = ccs.fmodf(locCurrentPercent, 1); 411 this._currentFrame = ccs.fmodf(this._currentFrame, this._nextFrameIndex); 412 this._toIndex = 0; 413 this.callMovementEvent([this._armature, ccs.MovementEventType.loopComplete, this._movementID]); 414 break; 415 } 416 this._currentPercent = locCurrentPercent; 417 } 418 }, 419 420 /** 421 * Get current movementID 422 * @returns {String} 423 */ 424 getCurrentMovementID: function () { 425 if (this._isComplete) 426 return ""; 427 return this._movementID; 428 }, 429 430 /** 431 * connect a event 432 * @param {Object} target 433 * @param {function} callFunc 434 */ 435 setMovementEventCallFunc:function (callFunc, target) { 436 this._movementEvent = new ccs.AnimationEvent(target, callFunc); 437 }, 438 439 /** 440 * call event 441 * @param {Array} args 442 */ 443 callMovementEvent:function (args) { 444 if (this._movementEvent) { 445 this._movementEvent.setArguments(args); 446 this._movementEvent.call(); 447 } 448 }, 449 450 /** 451 * connect a event 452 * @param {Object} target 453 * @param {function} callFunc 454 */ 455 setFrameEventCallFunc:function (callFunc, target) { 456 this._frameEvent = new ccs.AnimationEvent(target, callFunc); 457 }, 458 459 /** 460 * call event 461 * @param {Array} args 462 */ 463 callFrameEvent:function (args) { 464 if (this._frameEvent) { 465 this._frameEvent.setArguments(args); 466 this._frameEvent.call(); 467 } 468 }, 469 470 /** 471 * @param {ccs.Bone} bone 472 * @param {String} frameEventName 473 * @param {Number} originFrameIndex 474 * @param {Number} currentFrameIndex 475 */ 476 frameEvent:function(bone, frameEventName, originFrameIndex, currentFrameIndex){ 477 if (this._frameEvent) { 478 var frameEvent = new ccs.FrameEvent(); 479 frameEvent.bone = bone; 480 frameEvent.frameEventName = frameEventName; 481 frameEvent.originFrameIndex = originFrameIndex; 482 frameEvent.currentFrameIndex = currentFrameIndex; 483 this._frameEventQueue.push(frameEvent); 484 } 485 }, 486 487 /** 488 * animationData setter 489 * @param {ccs.AnimationData} aniData 490 */ 491 setAnimationData:function (aniData) { 492 this._animationData = aniData; 493 }, 494 495 /** 496 * animationData getter 497 * @return {ccs.AnimationData} 498 */ 499 getAnimationData:function () { 500 return this._animationData; 501 }, 502 /** 503 * userObject setter 504 * @param {Object} aniData 505 */ 506 setUserObject:function (userObject) { 507 this._userObject = userObject; 508 }, 509 510 /** 511 * userObject getter 512 * @return {Object} 513 */ 514 getUserObject:function () { 515 return this._userObject; 516 }, 517 518 /** 519 * Determines if the frame event is ignore 520 * @returns {boolean} 521 */ 522 isIgnoreFrameEvent:function(){ 523 return this._ignoreFrameEvent; 524 }, 525 526 /** 527 * Sets whether the frame event is ignore 528 * @param {Boolean} bool 529 */ 530 setIgnoreFrameEvent:function(bool){ 531 this._ignoreFrameEvent = bool; 532 } 533 }); 534 535 /** 536 * allocates and initializes a ArmatureAnimation. 537 * @constructs 538 * @return {ccs.ArmatureAnimation} 539 * @example 540 * // example 541 * var animation = ccs.ArmatureAnimation.create(); 542 */ 543 ccs.ArmatureAnimation.create = function (armature) { 544 var animation = new ccs.ArmatureAnimation(); 545 if (animation && animation.init(armature)) { 546 return animation; 547 } 548 return null; 549 };