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 * Base class for ccs.Bone objects. 27 * @class 28 * @extends ccs.NodeRGBA 29 */ 30 ccs.Bone = ccs.NodeRGBA.extend(/** @lends ccs.Bone# */{ 31 _boneData:null, 32 _armature:null, 33 _childArmature:null, 34 _displayManager:null, 35 _ignoreMovementBoneData:false, 36 _tween:null, 37 _tweenData:null, 38 _name:"", 39 _childrenBone:null, 40 _parentBone:null, 41 _boneTransformDirty:false, 42 _worldTransform:null, 43 _blendType:0, 44 _worldInfo:null, 45 _armatureParentBone:null, 46 _dataVersion:0, 47 ctor:function () { 48 cc.NodeRGBA.prototype.ctor.call(this); 49 this._boneData = null; 50 this._armature = null; 51 this._childArmature = null; 52 this._displayManager = null; 53 this._ignoreMovementBoneData = false; 54 this._tween = null; 55 this._tweenData = null; 56 this._name = ""; 57 this._childrenBone = []; 58 this._parentBone = null; 59 this._boneTransformDirty = true; 60 this._worldTransform = cc.AffineTransformMake(1, 0, 0, 1, 0, 0); 61 this._blendType=ccs.BlendType.normal; 62 }, 63 64 /** 65 * release objects 66 */ 67 release:function () { 68 CC_SAFE_RELEASE(this._tweenData); 69 for (var i = 0; i < this._childrenBone.length; i++) { 70 CC_SAFE_RELEASE(this._childrenBone[i]); 71 } 72 this._childrenBone = []; 73 CC_SAFE_RELEASE(this._tween); 74 CC_SAFE_RELEASE(this._displayManager); 75 CC_SAFE_RELEASE(this._boneData); 76 CC_SAFE_RELEASE(this._childArmature); 77 }, 78 79 /** 80 * Initializes a CCBone with the specified name 81 * @param {String} name 82 * @return {Boolean} 83 */ 84 init:function (name) { 85 cc.NodeRGBA.prototype.init.call(this); 86 if (name) { 87 this._name = name; 88 } 89 this._tweenData = new ccs.FrameData(); 90 this._tween = new ccs.Tween(); 91 this._tween.init(this); 92 this._displayManager = new ccs.DisplayManager(); 93 this._displayManager.init(this); 94 this._worldInfo = new ccs.BaseData(); 95 this._boneData = new ccs.BaseData(); 96 return true; 97 }, 98 99 /** 100 * set the boneData 101 * @param {ccs.BoneData} boneData 102 */ 103 setBoneData:function (boneData) { 104 if (!boneData) { 105 cc.log("boneData must not be null"); 106 return; 107 } 108 this._boneData = boneData; 109 this._name = this._boneData.name; 110 this._zOrder = this._boneData.zOrder; 111 this._displayManager.initDisplayList(boneData); 112 }, 113 114 /** 115 * boneData getter 116 * @return {ccs.BoneData} 117 */ 118 getBoneData:function () { 119 return this._boneData; 120 }, 121 122 /** 123 * set the armature 124 * @param {ccs.Armature} armature 125 */ 126 setArmature:function (armature) { 127 this._armature = armature; 128 if(armature){ 129 this._tween.setAnimation(this._armature.getAnimation()); 130 this._dataVersion = this._armature.getArmatureData().dataVersion; 131 this._armatureParentBone = this._armature.getParentBone(); 132 }else{ 133 this._armatureParentBone = null; 134 } 135 }, 136 137 /** 138 * armature getter 139 * @return {ccs.Armature} 140 */ 141 getArmature:function () { 142 return this._armature; 143 }, 144 145 /** 146 * update worldTransform 147 * @param dt 148 */ 149 update:function (dt) { 150 var locParentBone = this._parentBone; 151 var locArmature = this._armature; 152 var locTweenData = this._tweenData; 153 var locWorldTransform = this._worldTransform; 154 var locWorldInfo = this._worldInfo; 155 var locArmatureParentBone = this._armatureParentBone; 156 157 if (locParentBone) { 158 this._boneTransformDirty = this._boneTransformDirty || locParentBone.isTransformDirty(); 159 } 160 if (locArmatureParentBone && !this._boneTransformDirty){ 161 this._boneTransformDirty = locArmatureParentBone.isTransformDirty(); 162 } 163 if (this._boneTransformDirty) { 164 if (this._dataVersion >= ccs.CONST_VERSION_COMBINED) { 165 var locBoneData = this._boneData; 166 locTweenData.x += locBoneData.x; 167 locTweenData.y += locBoneData.y; 168 locTweenData.skewX += locBoneData.skewX; 169 locTweenData.skewY += locBoneData.skewY; 170 locTweenData.scaleX += locBoneData.scaleX; 171 locTweenData.scaleY += locBoneData.scaleY; 172 173 locTweenData.scaleX -= 1; 174 locTweenData.scaleY -= 1; 175 } 176 177 locWorldInfo.x = locTweenData.x + this._position.x; 178 locWorldInfo.y = locTweenData.y + this._position.y; 179 locWorldInfo.scaleX = locTweenData.scaleX * this._scaleX; 180 locWorldInfo.scaleY = locTweenData.scaleY * this._scaleY; 181 locWorldInfo.skewX = locTweenData.skewX + this._skewX + this._rotationX; 182 locWorldInfo.skewY = locTweenData.skewY + this._skewY - this._rotationY; 183 184 if (this._parentBone) { 185 this.applyParentTransform(this._parentBone); 186 } 187 else { 188 if (locArmatureParentBone) { 189 this.applyParentTransform(locArmatureParentBone); 190 } 191 } 192 193 ccs.TransformHelp.nodeToMatrix(locWorldInfo, locWorldTransform); 194 195 if (locArmatureParentBone) { 196 this._worldTransform = cc.AffineTransformConcat(locWorldTransform, locArmature.nodeToParentTransform()); 197 } 198 } 199 ccs.DisplayFactory.updateDisplay(this, dt, this._boneTransformDirty || locArmature.getArmatureTransformDirty()); 200 201 var locChildrenBone = this._childrenBone; 202 for (var i = 0; i < locChildrenBone.length; i++) { 203 locChildrenBone[i].update(dt); 204 } 205 this._boneTransformDirty = false; 206 }, 207 208 applyParentTransform: function (parent) { 209 var locWorldInfo = this._worldInfo; 210 var locParentWorldTransform = parent._worldTransform; 211 var locParentWorldInfo = parent._worldInfo; 212 var x = locWorldInfo.x; 213 var y = locWorldInfo.y; 214 locWorldInfo.x = x * locParentWorldTransform.a + y * locParentWorldTransform.c + locParentWorldInfo.x; 215 locWorldInfo.y = x * locParentWorldTransform.b + y * locParentWorldTransform.d + locParentWorldInfo.y; 216 locWorldInfo.scaleX = locWorldInfo.scaleX * locParentWorldInfo.scaleX; 217 locWorldInfo.scaleY = locWorldInfo.scaleY * locParentWorldInfo.scaleY; 218 locWorldInfo.skewX = locWorldInfo.skewX + locParentWorldInfo.skewX; 219 locWorldInfo.skewY = locWorldInfo.skewY + locParentWorldInfo.skewY; 220 }, 221 222 /** 223 * Rewrite visit ,when node draw, g_NumberOfDraws is changeless 224 */ 225 visit:function (ctx) { 226 var node = this.getDisplayManager().getDisplayRenderNode(); 227 if (node) { 228 node.visit(ctx); 229 } 230 }, 231 232 /** 233 * update display color 234 * @param {cc.c3b} color 235 */ 236 updateDisplayedColor:function (color) { 237 this._realColor = cc.c3b(255,255,255); 238 cc.NodeRGBA.prototype.updateDisplayedColor.call(this, color); 239 this.updateColor(); 240 }, 241 242 /** 243 * update display opacity 244 * @param {Number} opacity 245 */ 246 updateDisplayedOpacity:function (opacity) { 247 this._realOpacity = 255; 248 cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, opacity); 249 this.updateColor(); 250 }, 251 252 /** 253 * set display color 254 * @param {cc.c3b} color 255 */ 256 setColor: function (color) { 257 cc.NodeRGBA.prototype.setColor.call(this, color); 258 this.updateColor(); 259 }, 260 261 /** 262 * set display opacity 263 * @param {Number} opacity 0-255 264 */ 265 setOpacity: function (opacity) { 266 cc.NodeRGBA.prototype.setOpacity.call(this, opacity); 267 this.updateColor(); 268 }, 269 270 /** 271 * update display color 272 */ 273 updateColor:function () { 274 var display = this._displayManager.getDisplayRenderNode(); 275 if (display && display.RGBAProtocol) { 276 var locDisplayedColor = this._displayedColor; 277 var locTweenData = this._tweenData; 278 var locOpacity = this._displayedOpacity * locTweenData.a / 255; 279 var locColor = cc.c3b(locDisplayedColor.r * locTweenData.r / 255, locDisplayedColor.g * locTweenData.g / 255, locDisplayedColor.b * locTweenData.b / 255); 280 display.setOpacity(locOpacity); 281 display.setColor(locColor); 282 } 283 }, 284 285 /** 286 * update display zOrder 287 */ 288 updateZOrder: function () { 289 if (this._armature.getArmatureData().dataVersion >= ccs.CONST_VERSION_COMBINED) { 290 var zorder = this._tweenData.zOrder + this._boneData.zOrder; 291 this.setZOrder(zorder); 292 } 293 else { 294 this.setZOrder(this._tweenData.zOrder); 295 } 296 }, 297 298 /** 299 * Add a child to this bone, and it will let this child call setParent(ccs.Bone) function to set self to it's parent 300 * @param {ccs.Bone} child 301 */ 302 addChildBone:function (child) { 303 if (!child) { 304 cc.log("Argument must be non-nil"); 305 return; 306 } 307 if (child._parentBone) { 308 cc.log("child already added. It can't be added again"); 309 return; 310 } 311 if (cc.ArrayGetIndexOfObject(this._childrenBone, child) < 0) { 312 this._childrenBone.push(child); 313 child.setParentBone(this); 314 } 315 }, 316 317 /** 318 * Removes a child bone 319 * @param {ccs.Bone} bone 320 * @param {Boolean} recursion 321 */ 322 removeChildBone:function (bone, recursion) { 323 for (var i = 0; i < this._childrenBone.length; i++) { 324 if (this._childrenBone[i] == bone) { 325 if (recursion) { 326 var ccbones = bone._childrenBone; 327 for (var j = 0; j < ccbones.length; j++) { 328 bone.removeChildBone(ccbones[j], recursion); 329 } 330 } 331 bone.setParentBone(null); 332 bone.getDisplayManager().setCurrentDecorativeDisplay(null); 333 cc.ArrayRemoveObject(this._childrenBone, bone); 334 } 335 } 336 }, 337 338 /** 339 * Remove itself from its parent CCBone. 340 * @param {Boolean} recursion 341 */ 342 removeFromParent:function (recursion) { 343 if (this._parentBone) { 344 this._parentBone.removeChildBone(this, recursion); 345 } 346 }, 347 348 /** 349 * Set parent bone. 350 * If _parent is NUll, then also remove this bone from armature. 351 * It will not set the CCArmature, if you want to add the bone to a CCArmature, you should use ccs.Armature.addBone(bone, parentName). 352 * @param {ccs.Bone} parent the parent bone. 353 */ 354 setParentBone:function (parent) { 355 this._parentBone = parent; 356 }, 357 358 /** 359 * parent bone getter 360 * @return {ccs.Bone} 361 */ 362 getParentBone:function () { 363 return this._parentBone; 364 }, 365 366 /** 367 * child armature setter 368 * @param {ccs.Armature} armature 369 */ 370 setChildArmature:function (armature) { 371 if (this._childArmature != armature) { 372 if (armature == null && this._childArmature) { 373 this._childArmature.setParentBone(null); 374 } 375 this._childArmature = armature; 376 } 377 }, 378 379 /** 380 * child armature getter 381 * @return {ccs.Armature} 382 */ 383 getChildArmature:function () { 384 return this._childArmature; 385 }, 386 387 /** 388 * child bone getter 389 * @return {Array} 390 */ 391 getChildrenBone:function () { 392 return this._childrenBone; 393 }, 394 395 /** 396 * tween getter 397 * @return {ccs.Tween} 398 */ 399 getTween:function () { 400 return this._tween; 401 }, 402 403 /** 404 * zOrder setter 405 * @param {Number} 406 */ 407 setZOrder:function (zOrder) { 408 if (this._zOrder != zOrder) 409 cc.Node.prototype.setZOrder.call(this, zOrder); 410 }, 411 412 /** 413 * transform dirty setter 414 * @param {Boolean} 415 */ 416 setTransformDirty:function (dirty) { 417 this._boneTransformDirty = dirty; 418 }, 419 420 /** 421 * transform dirty getter 422 * @return {Boolean} 423 */ 424 isTransformDirty:function () { 425 return this._boneTransformDirty; 426 }, 427 428 /** 429 * return world transform 430 * @return {{a:0.b:0,c:0,d:0,tx:0,ty:0}} 431 */ 432 nodeToArmatureTransform:function () { 433 return this._worldTransform; 434 }, 435 436 /** 437 * Returns the world affine transform matrix. The matrix is in Pixels. 438 * @returns {cc.AffineTransform} 439 */ 440 nodeToWorldTransform: function () { 441 return cc.AffineTransformConcat(this._worldTransform, this._armature.nodeToWorldTransform()); 442 }, 443 444 /** 445 * get render node 446 * @returns {cc.Node} 447 */ 448 getDisplayRenderNode: function () { 449 return this._displayManager.getDisplayRenderNode(); 450 }, 451 452 /** 453 * get render node type 454 * @returns {Number} 455 */ 456 getDisplayRenderNodeType: function () { 457 return this._displayManager.getDisplayRenderNodeType(); 458 }, 459 460 /** 461 * Add display and use _displayData init the display. 462 * If index already have a display, then replace it. 463 * If index is current display index, then also change display to _index 464 * @param {cc.Display} displayData it include the display information, like DisplayType. 465 * If you want to create a sprite display, then create a CCSpriteDisplayData param 466 *@param {Number} index the index of the display you want to replace or add to 467 * -1 : append display from back 468 */ 469 addDisplay:function (displayData, index) { 470 index = index || 0; 471 return this._displayManager.addDisplay(displayData, index); 472 }, 473 474 /** 475 * remove display 476 * @param {Number} index 477 */ 478 removeDisplay: function (index) { 479 this._displayManager.removeDisplay(index); 480 }, 481 482 addSkin:function (skin, index) { 483 index = index||0; 484 return this._displayManager.addSkin(skin, index); 485 }, 486 487 /** 488 * change display by index 489 * @param {Number} index 490 * @param {Boolean} force 491 */ 492 changeDisplayByIndex:function (index, force) { 493 this._displayManager.changeDisplayByIndex(index, force); 494 }, 495 496 /** 497 * get the collider body list in this bone. 498 * @returns {*} 499 */ 500 getColliderBodyList: function () { 501 var decoDisplay = this._displayManager.getCurrentDecorativeDisplay() 502 if (decoDisplay) { 503 var detector = decoDisplay.getColliderDetector() 504 if (detector) { 505 return detector.getColliderBodyList(); 506 } 507 } 508 return null; 509 }, 510 511 /** 512 * collider filter setter 513 * @param {cc.ColliderFilter} filter 514 */ 515 setColliderFilter: function (filter) { 516 var displayList = this._displayManager.getDecorativeDisplayList(); 517 for (var i = 0; i < displayList.length; i++) { 518 var locDecoDisplay = displayList[i]; 519 var locDetector = locDecoDisplay.getColliderDetector(); 520 if (locDetector) { 521 locDetector.setColliderFilter(filter); 522 } 523 } 524 525 }, 526 527 /** 528 * collider filter getter 529 * @returns {cc.ColliderFilter} 530 */ 531 getColliderFilter: function () { 532 var decoDisplay = this._displayManager.getCurrentDecorativeDisplay(); 533 if (decoDisplay) { 534 var detector = decoDisplay.getColliderDetector(); 535 if (detector) { 536 return detector.getColliderFilter(); 537 } 538 } 539 return null; 540 }, 541 542 /** 543 * displayManager setter 544 * @param {ccs.DisplayManager} 545 */ 546 setDisplayManager:function (displayManager) { 547 this._displayManager = displayManager; 548 }, 549 550 /** 551 * displayManager dirty getter 552 * @return {ccs.DisplayManager} 553 */ 554 getDisplayManager:function () { 555 return this._displayManager; 556 }, 557 558 /** 559 * When CCArmature play a animation, if there is not a CCMovementBoneData of this bone in this CCMovementData, this bone will hide. 560 * Set IgnoreMovementBoneData to true, then this bone will also show. 561 * @param {Boolean} bool 562 */ 563 setIgnoreMovementBoneData:function (bool) { 564 this._ignoreMovementBoneData = bool; 565 }, 566 567 /** 568 * ignoreMovementBoneData getter 569 * @return {Boolean} 570 */ 571 getIgnoreMovementBoneData:function () { 572 return this._ignoreMovementBoneData; 573 }, 574 575 /** 576 * tweenData getter 577 * @return {ccs.FrameData} 578 */ 579 getTweenData:function () { 580 return this._tweenData; 581 }, 582 583 /** 584 * name setter 585 * @param {String} name 586 */ 587 setName:function (name) { 588 this._name = name; 589 }, 590 591 /** 592 * name getter 593 * @return {String} 594 */ 595 getName:function () { 596 return this._name; 597 }, 598 599 /** 600 * blendType setter 601 * @param {ccs.BlendType} blendType 602 */ 603 setBlendType:function (blendType) { 604 this._blendType = blendType; 605 }, 606 607 /** 608 * blendType getter 609 * @return {ccs.BlendType} 610 */ 611 getBlendType:function () { 612 return this._blendType; 613 } 614 }); 615 616 /** 617 * allocates and initializes a bone. 618 * @constructs 619 * @return {ccs.Bone} 620 * @example 621 * // example 622 * var bone = ccs.Bone.create(); 623 */ 624 ccs.Bone.create = function (name) { 625 var bone = new ccs.Bone(); 626 if (bone && bone.init(name)) { 627 return bone; 628 } 629 return null; 630 };