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 * Default Node tag 29 * @constant 30 * @type Number 31 */ 32 cc.NODE_TAG_INVALID = -1; 33 /** 34 * Node on enter 35 * @constant 36 */ 37 cc.NODE_ON_ENTER = null; 38 /** 39 * Node on exit 40 * @constant 41 */ 42 cc.NODE_ON_EXIT = null; 43 44 /** 45 * XXX: Yes, nodes might have a sort problem once every 15 days if the game runs at 60 FPS and each frame sprites are reordered. 46 * @type Number 47 */ 48 cc.s_globalOrderOfArrival = 1; 49 50 /** <p>cc.Node is the main element. Anything thats gets drawn or contains things that get drawn is a cc.Node.<br/> 51 The most popular cc.Nodes are: cc.Scene, cc.Layer, cc.Sprite, cc.Menu.<br/></p> 52 53 <p>The main features of a cc.Node are: <br/> 54 - They can contain other cc.Node nodes (addChild, getChildByTag, removeChild, etc) <br/> 55 - They can schedule periodic callback (schedule, unschedule, etc) <br/> 56 - They can execute actions (runAction, stopAction, etc) <br/></p> 57 58 <p>Some cc.Node nodes provide extra functionality for them or their children.</p> 59 60 <p>Subclassing a cc.Node usually means (one/all) of: <br/> 61 - overriding init to initialize resources and schedule callbacks <br/> 62 - create callbacks to handle the advancement of time <br/> 63 - overriding draw to render the node <br/></p> 64 65 <p>Features of cc.Node: <br/> 66 - position <br/> 67 - scale (x, y) <br/> 68 - rotation (in degrees, clockwise) <br/> 69 - anchor point<br/> 70 - size <br/> 71 - visible<br/> 72 - z-order <br/> 73 - openGL z position <br/></P> 74 75 <p> Default values: <br/> 76 - rotation: 0 <br/> 77 - position: (x=0,y=0) <br/> 78 - scale: (x=1,y=1) <br/> 79 - contentSize: (x=0,y=0)<br/> 80 - anchorPoint: (x=0,y=0)<br/></p> 81 82 <p> Limitations:<br/> 83 - A cc.Node is a "void" object. It doesn't have a texture <br/></P> 84 85 <p>Order in transformations with grid disabled <br/> 86 -# The node will be translated (position) <br/> 87 -# The node will be rotated (rotation)<br/> 88 -# The node will be scaled (scale) <br/> 89 90 <p>Order in transformations with grid enabled<br/> 91 -# The node will be translated (position)<br/> 92 -# The node will be rotated (rotation) <br/> 93 -# The node will be scaled (scale) <br/> 94 -# The grid will capture the screen <br/> 95 -# The node will be moved according to the camera values (camera) <br/> 96 -# The grid will render the captured screen <br/></P> 97 * @class 98 * @extends cc.Class 99 * @example 100 * // example 101 * cc.Sprite = cc.Node.extend({}); 102 * cc.Sprite.initWithImage = function(){ 103 * }; 104 */ 105 cc.Node = cc.Class.extend(/** @lends cc.Node# */{ 106 _zOrder:0, 107 _vertexZ:0.0, 108 109 _rotationX:0, 110 _rotationY:0.0, 111 _scaleX:1.0, 112 _scaleY:1.0, 113 _position:null, 114 _skewX:0.0, 115 _skewY:0.0, 116 // children (lazy allocs), 117 _children:null, 118 // lazy alloc, 119 _visible:true, 120 _anchorPoint:null, 121 _anchorPointInPoints:null, 122 _contentSize:null, 123 _running:false, 124 _parent:null, 125 // "whole screen" objects. like Scenes and Layers, should set _ignoreAnchorPointForPosition to true 126 _ignoreAnchorPointForPosition:false, 127 _tag:cc.NODE_TAG_INVALID, 128 // userData is always inited as nil 129 _userData:null, 130 _userObject:null, 131 _transformDirty:true, 132 _inverseDirty:true, 133 _cacheDirty:true, 134 _transformGLDirty:null, 135 _transform:null, 136 _inverse:null, 137 138 //since 2.0 api 139 _reorderChildDirty:false, 140 _shaderProgram:null, 141 _orderOfArrival:0, 142 143 _actionManager:null, 144 _scheduler:null, 145 146 _initializedNode:false, 147 _additionalTransformDirty:false, 148 _additionalTransform:null, 149 _componentContainer:null, 150 _isTransitionFinished:false, 151 152 _rotationRadiansX:0, 153 _rotationRadiansY:0, 154 155 _initNode:function () { 156 this._anchorPoint = cc.p(0, 0); 157 this._anchorPointInPoints = cc.p(0, 0); 158 this._contentSize = cc.size(0, 0); 159 this._position = cc.p(0, 0); 160 this._children = []; 161 162 var director = cc.Director.getInstance(); 163 this._actionManager = director.getActionManager(); 164 this._scheduler = director.getScheduler(); 165 this._initializedNode = true; 166 this._additionalTransform = cc.AffineTransformMakeIdentity(); 167 this._componentContainer = new cc.ComponentContainer(this); 168 }, 169 170 /** 171 * Initializes the instance of cc.Node 172 * @returns {boolean} Whether the initialization was successful. 173 */ 174 init:function () { 175 if (this._initializedNode === false) 176 this._initNode(); 177 return true; 178 }, 179 180 /** 181 * @param {Array} array 182 * @param {cc.Node.StateCallbackType} callbackType 183 * @private 184 */ 185 _arrayMakeObjectsPerformSelector:function (array, callbackType) { 186 if (!array || array.length === 0) 187 return; 188 189 var i, len = array.length,node; 190 var nodeCallbackType = cc.Node.StateCallbackType; 191 switch (callbackType) { 192 case nodeCallbackType.onEnter: 193 for (i = 0; i < len; i++) { 194 node = array[i]; 195 if (node) 196 node.onEnter(); 197 } 198 break; 199 case nodeCallbackType.onExit: 200 for (i = 0; i < len; i++) { 201 node = array[i]; 202 if (node) 203 node.onExit(); 204 } 205 break; 206 case nodeCallbackType.onEnterTransitionDidFinish: 207 for (i = 0; i < len; i++) { 208 node = array[i]; 209 if (node) 210 node.onEnterTransitionDidFinish(); 211 } 212 break; 213 case nodeCallbackType.cleanup: 214 for (i = 0; i < len; i++) { 215 node = array[i]; 216 if (node) 217 node.cleanup(); 218 } 219 break; 220 case nodeCallbackType.updateTransform: 221 for (i = 0; i < len; i++) { 222 node = array[i]; 223 if (node) 224 node.updateTransform(); 225 } 226 break; 227 case nodeCallbackType.onExitTransitionDidStart: 228 for (i = 0; i < len; i++) { 229 node = array[i]; 230 if (node) 231 node.onExitTransitionDidStart(); 232 } 233 break; 234 case nodeCallbackType.sortAllChildren: 235 for (i = 0; i < len; i++) { 236 node = array[i]; 237 if (node) 238 node.sortAllChildren(); 239 } 240 break; 241 default : 242 throw "Unknown callback function"; 243 break; 244 } 245 }, 246 247 /** 248 * set the dirty node 249 */ 250 setNodeDirty:null, 251 252 _setNodeDirtyForCanvas:function () { 253 this._setNodeDirtyForCache(); 254 if(this._transformDirty === false) 255 this._transformDirty = this._inverseDirty = true; 256 }, 257 258 _setNodeDirtyForWebGL:function () { 259 if(this._transformDirty === false) 260 this._transformDirty = this._inverseDirty = true; 261 }, 262 263 /** 264 * <p>get the skew degrees in X </br> 265 * The X skew angle of the node in degrees. <br/> 266 * This angle describes the shear distortion in the X direction.<br/> 267 * Thus, it is the angle between the Y axis and the left edge of the shape </br> 268 * The default skewX angle is 0. Positive values distort the node in a CW direction.</br> 269 * </p> 270 * @return {Number} The X skew angle of the node in degrees. 271 */ 272 getSkewX:function () { 273 return this._skewX; 274 }, 275 276 /** 277 * <p> 278 * Changes the X skew angle of the node in degrees. <br/> 279 * <br/> 280 * This angle describes the shear distortion in the X direction. <br/> 281 * Thus, it is the angle between the Y axis and the left edge of the shape <br/> 282 * The default skewX angle is 0. Positive values distort the node in a CW direction. 283 * </p> 284 * @param {Number} newSkewX The X skew angle of the node in degrees. 285 */ 286 setSkewX:function (newSkewX) { 287 this._skewX = newSkewX; 288 this.setNodeDirty(); 289 }, 290 291 /** 292 * <p>get the skew degrees in Y <br/> 293 * The Y skew angle of the node in degrees. <br/> 294 * This angle describes the shear distortion in the Y direction. <br/> 295 * Thus, it is the angle between the X axis and the bottom edge of the shape <br/> 296 * The default skewY angle is 0. Positive values distort the node in a CCW direction. <br/> 297 * </p> 298 * @return {Number} The Y skew angle of the node in degrees. 299 */ 300 getSkewY:function () { 301 return this._skewY; 302 }, 303 304 /** 305 * <p> 306 * Changes the Y skew angle of the node in degrees. 307 * 308 * This angle describes the shear distortion in the Y direction. 309 * Thus, it is the angle between the X axis and the bottom edge of the shape 310 * The default skewY angle is 0. Positive values distort the node in a CCW direction. 311 * </p> 312 * @param {Number} newSkewY The Y skew angle of the node in degrees. 313 */ 314 setSkewY:function (newSkewY) { 315 this._skewY = newSkewY; 316 this.setNodeDirty(); 317 }, 318 319 /** 320 * zOrder getter 321 * @return {Number} 322 */ 323 getZOrder:function () { 324 return this._zOrder; 325 }, 326 327 /** 328 * <p> 329 * Sets the z order which stands for the drawing order <br/> 330 * <br/> 331 * This is an internal method. Don't call it outside the framework. <br/> 332 * The difference between setZOrder(int) and _setOrder(int) is: <br/> 333 * - _setZOrder(int) is a pure setter for m_nZOrder memeber variable <br/> 334 * - setZOrder(int) firstly changes m_nZOrder, then recorder this node in its parent's chilren array. 335 * </p> 336 * @param {Number} z 337 * @private 338 */ 339 _setZOrder:function (z) { 340 this._zOrder = z; 341 }, 342 343 /** 344 * <p> 345 * Sets the Z order which stands for the drawing order, and reorder this node in its parent's children array. <br/> 346 * <br/> 347 * The Z order of node is relative to its "brothers": children of the same parent. <br/> 348 * It's nothing to do with OpenGL's z vertex. This one only affects the draw order of nodes in cocos2d. <br/> 349 * The larger number it is, the later this node will be drawn in each message loop. <br/> 350 * Please refer to setVertexZ(float) for the difference. 351 * </p> 352 * @param {Number} z Z order of this node. 353 */ 354 setZOrder:function (z) { 355 this._setZOrder(z); 356 if (this._parent) 357 this._parent.reorderChild(this, z); 358 }, 359 360 /** 361 * Gets WebGL Z vertex of this node. 362 * @return {Number} WebGL Z vertex of this node 363 */ 364 getVertexZ:function () { 365 return this._vertexZ; 366 }, 367 368 /** 369 * <p> 370 * Sets the real WebGL Z vertex. <br/> 371 * <br/> 372 * Differences between openGL Z vertex and cocos2d Z order: <br/> 373 * - OpenGL Z modifies the Z vertex, and not the Z order in the relation between parent-children <br/> 374 * - OpenGL Z might require to set 2D projection <br/> 375 * - cocos2d Z order works OK if all the nodes uses the same openGL Z vertex. eg: vertexZ = 0 <br/> 376 * <br/> 377 * @warning Use it at your own risk since it might break the cocos2d parent-children z order 378 * </p> 379 * @param {Number} Var 380 */ 381 setVertexZ:function (Var) { 382 this._vertexZ = Var; 383 }, 384 385 /** 386 * The rotation (angle) of the node in degrees. 0 is the default rotation angle. Positive values rotate node CW. 387 * @return {Number} The rotation of the node in degrees. 388 */ 389 getRotation:function () { 390 cc.Assert(this._rotationX == this._rotationY, "CCNode#rotation. RotationX != RotationY. Don't know which one to return"); 391 return this._rotationX; 392 }, 393 394 /** 395 * <p> 396 * Sets the rotation (angle) of the node in degrees. <br/> 397 * <br/> 398 * 0 is the default rotation angle. <br/> 399 * Positive values rotate node clockwise, and negative values for anti-clockwise. 400 * </p> 401 * @param {Number} newRotation The rotation of the node in degrees. 402 */ 403 setRotation:function (newRotation) { 404 this._rotationX = this._rotationY = newRotation; 405 this._rotationRadiansX = this._rotationX * 0.017453292519943295; //(Math.PI / 180); 406 this._rotationRadiansY = this._rotationY * 0.017453292519943295; //(Math.PI / 180); 407 this.setNodeDirty(); 408 }, 409 410 /** 411 * The rotation (angle) of the node in degrees. 0 is the default rotation angle. <br/> 412 * Positive values rotate node CW. It only modifies the X rotation performing a horizontal rotational skew . 413 * (support only in WebGl rendering mode) 414 * @return {Number} The X rotation in degrees. 415 */ 416 getRotationX:function () { 417 return this._rotationX; 418 }, 419 420 /** 421 * <p> 422 * Sets the X rotation (angle) of the node in degrees which performs a horizontal rotational skew. <br/> 423 * <br/> 424 * 0 is the default rotation angle. <br/> 425 * Positive values rotate node clockwise, and negative values for anti-clockwise. 426 * </p> 427 * @param {Number} rotationX The X rotation in degrees which performs a horizontal rotational skew. 428 */ 429 setRotationX:function (rotationX) { 430 this._rotationX = rotationX; 431 this._rotationRadiansX = this._rotationX * 0.017453292519943295; //(Math.PI / 180); 432 this.setNodeDirty(); 433 }, 434 435 /** 436 * The rotation (angle) of the node in degrees. 0 is the default rotation angle. <br/> 437 * Positive values rotate node CW. It only modifies the Y rotation performing a vertical rotational skew . 438 * @return {Number} The Y rotation in degrees. 439 */ 440 getRotationY:function () { 441 return this._rotationY; 442 }, 443 444 /** 445 * <p> 446 * Sets the Y rotation (angle) of the node in degrees which performs a vertical rotational skew. <br/> 447 * <br/> 448 * 0 is the default rotation angle. <br/> 449 * Positive values rotate node clockwise, and negative values for anti-clockwise. 450 * </p> 451 * @param rotationY The Y rotation in degrees. 452 */ 453 setRotationY:function (rotationY) { 454 this._rotationY = rotationY; 455 this._rotationRadiansY = this._rotationY * 0.017453292519943295; //(Math.PI / 180); 456 this.setNodeDirty(); 457 }, 458 459 /** Get the scale factor of the node. 460 * @warning: Assert when _scaleX != _scaleY. 461 * @return {Number} 462 */ 463 getScale:function () { 464 cc.Assert(this._scaleX == this._scaleY, "cc.Node#scale. ScaleX != ScaleY. Don't know which one to return"); 465 return this._scaleX; 466 }, 467 468 /** 469 * The scale factor of the node. 1.0 is the default scale factor. It modifies the X and Y scale at the same time. 470 * @param {Number} scale or scaleX value 471 * @param {Number} [scaleY=] 472 */ 473 setScale:function (scale, scaleY) { 474 this._scaleX = scale; 475 this._scaleY = (scaleY || scaleY === 0) ? scaleY : scale; 476 this.setNodeDirty(); 477 }, 478 479 /** 480 * Returns the scale factor on X axis of this node 481 * @return {Number} The scale factor on X axis. 482 */ 483 getScaleX:function () { 484 return this._scaleX; 485 }, 486 487 /** 488 * <p> 489 * Changes the scale factor on X axis of this node <br/> 490 * The deafult value is 1.0 if you haven't changed it before 491 * </p> 492 * @param {Number} newScaleX The scale factor on X axis. 493 */ 494 setScaleX:function (newScaleX) { 495 this._scaleX = newScaleX; 496 this.setNodeDirty(); 497 }, 498 499 /** 500 * Returns the scale factor on Y axis of this node 501 * @return {Number} The scale factor on Y axis. 502 */ 503 getScaleY:function () { 504 return this._scaleY; 505 }, 506 507 /** 508 * <p> 509 * Changes the scale factor on Y axis of this node <br/> 510 * The Default value is 1.0 if you haven't changed it before. 511 * </p> 512 * @param {Number} newScaleY The scale factor on Y axis. 513 */ 514 setScaleY:function (newScaleY) { 515 this._scaleY = newScaleY; 516 this.setNodeDirty(); 517 }, 518 519 /** 520 * <p> 521 * Changes the position (x,y) of the node in OpenGL coordinates 522 * Usually we use ccp(x,y) to compose CCPoint object. 523 * The original point (0,0) is at the left-bottom corner of screen. 524 * and Passing two numbers (x,y) is much efficient than passing CCPoint object. 525 * </p> 526 * @param {cc.Point|Number} newPosOrxValue The position (x,y) of the node in coordinates or X coordinate for position 527 * @param {Number} yValue Y coordinate for position 528 * @example 529 * var size = cc.Director.getInstance().getWinSize(); 530 * node.setPosition( cc.p(size.width/2, size.height/2) ) 531 */ 532 setPosition:function (newPosOrxValue, yValue) { 533 var locPosition = this._position; 534 if (arguments.length == 2) { 535 locPosition.x = newPosOrxValue; 536 locPosition.y = yValue; 537 } else if (arguments.length == 1) { 538 locPosition.x = newPosOrxValue.x; 539 locPosition.y = newPosOrxValue.y; 540 } 541 this.setNodeDirty(); 542 }, 543 544 /** 545 * <p>Position (x,y) of the node in OpenGL coordinates. (0,0) is the left-bottom corner. </p> 546 * @const 547 * @return {cc.Point} The position (x,y) of the node in OpenGL coordinates 548 */ 549 getPosition:function () { 550 return cc.p(this._position.x, this._position.y); 551 }, 552 553 /** 554 * @return {Number} 555 */ 556 getPositionX:function () { 557 return this._position.x; 558 }, 559 560 /** 561 * @param {Number} x 562 */ 563 setPositionX:function (x) { 564 this._position.x = x; 565 this.setNodeDirty(); 566 }, 567 568 /** 569 * @return {Number} 570 */ 571 getPositionY:function () { 572 return this._position.y; 573 }, 574 575 /** 576 * @param {Number} y 577 */ 578 setPositionY:function (y) { 579 this._position.y = y; 580 this.setNodeDirty(); 581 }, 582 583 /** 584 * Get the amount of children. 585 * @return {Number} The amount of children. 586 */ 587 getChildrenCount:function () { 588 return this._children.length; 589 }, 590 591 /** 592 * Return an array of children <br/> 593 * Composing a "tree" structure is a very important feature of CCNode 594 * @return {Array} An array of children 595 * @example 596 * //This sample code traverses all children nodes, and set theie position to (0,0) 597 * var allChildren = parent.getChildren(); 598 * for(var i = 0; i< allChildren.length; i++) { 599 * allChildren[i].setPosition(0,0); 600 * } 601 */ 602 getChildren:function () { 603 return this._children; 604 }, 605 606 /** 607 * Determines if the node is visible 608 * @see setVisible(bool) 609 * @return {Boolean} true if the node is visible, false if the node is hidden. 610 */ 611 isVisible:function () { 612 return this._visible; 613 }, 614 615 /** 616 * Sets whether the node is visible <br/> 617 * The default value is true, a node is default to visible 618 * @param {Boolean} Var true if the node is visible, false if the node is hidden. 619 */ 620 setVisible:function (Var) { 621 this._visible = Var; 622 this.setNodeDirty(); 623 }, 624 625 /** 626 * <p>anchorPoint is the point around which all transformations and positioning manipulations take place.<br/> 627 * It's like a pin in the node where it is "attached" to its parent. <br/> 628 * The anchorPoint is normalized, like a percentage. (0,0) means the bottom-left corner and (1,1) means the top-right corner. <br/> 629 * But you can use values higher than (1,1) and lower than (0,0) too. <br/> 630 * The default anchorPoint is (0.5,0.5), so it starts in the center of the node. <br/></p> 631 * @const 632 * @return {cc.Point} The anchor point of node. 633 */ 634 getAnchorPoint:function () { 635 return cc.p(this._anchorPoint.x, this._anchorPoint.y); 636 }, 637 638 /** 639 * <p> 640 * Sets the anchor point in percent. <br/> 641 * <br/> 642 * anchorPoint is the point around which all transformations and positioning manipulations take place. <br/> 643 * It's like a pin in the node where it is "attached" to its parent. <br/> 644 * The anchorPoint is normalized, like a percentage. (0,0) means the bottom-left corner and (1,1) means the top-right corner. <br/> 645 * But you can use values higher than (1,1) and lower than (0,0) too. <br/> 646 * The default anchorPoint is (0.5,0.5), so it starts in the center of the node. 647 * </p> 648 * @param {cc.Point} point The anchor point of node. 649 */ 650 setAnchorPoint:function (point) { 651 var locAnchorPoint = this._anchorPoint; 652 if (!cc.pointEqualToPoint(point, locAnchorPoint)) { 653 locAnchorPoint.x = point.x; 654 locAnchorPoint.y = point.y; 655 var locAPP = this._anchorPointInPoints, locSize = this._contentSize; 656 locAPP.x = locSize.width * point.x; 657 locAPP.y = locSize.height * point.y; 658 this.setNodeDirty(); 659 } 660 }, 661 662 /** 663 * The anchorPoint in absolute pixels. <br/> 664 * you can only read it. If you wish to modify it, use anchorPoint instead 665 * @see getAnchorPoint() 666 * @const 667 * @return {cc.Point} The anchor point in absolute pixels. 668 */ 669 getAnchorPointInPoints:function () { 670 return cc.p(this._anchorPointInPoints.x, this._anchorPointInPoints.y); 671 }, 672 673 /** 674 * <p>The untransformed size of the node. <br/> 675 * The contentSize remains the same no matter the node is scaled or rotated.<br/> 676 * All nodes has a size. Layer and Scene has the same size of the screen. <br/></p> 677 * @const 678 * @return {cc.Size} The untransformed size of the node. 679 */ 680 getContentSize:function () { 681 return cc.size(this._contentSize.width, this._contentSize.height); 682 }, 683 684 /** 685 * <p> 686 * Sets the untransformed size of the node. <br/> 687 * <br/> 688 * The contentSize remains the same no matter the node is scaled or rotated. <br/> 689 * All nodes has a size. Layer and Scene has the same size of the screen. 690 * </p> 691 * @param {cc.Size} size The untransformed size of the node. 692 */ 693 setContentSize:function (size) { 694 var locContentSize = this._contentSize; 695 if (!cc.sizeEqualToSize(size, locContentSize)) { 696 locContentSize.width = size.width; 697 locContentSize.height = size.height; 698 var locAPP = this._anchorPointInPoints, locAnchorPoint = this._anchorPoint; 699 locAPP.x = locContentSize.width * locAnchorPoint.x; 700 locAPP.y = locContentSize.height * locAnchorPoint.y; 701 this.setNodeDirty(); 702 } 703 }, 704 705 /** 706 * <p> 707 * Returns whether or not the node accepts event callbacks. <br/> 708 * Running means the node accept event callbacks like onEnter(), onExit(), update() 709 * </p> 710 * @return {Boolean} Whether or not the node is running. 711 */ 712 isRunning:function () { 713 return this._running; 714 }, 715 716 /** 717 * Returns a pointer to the parent node 718 * @return {cc.Node} A pointer to the parnet node 719 */ 720 getParent:function () { 721 return this._parent; 722 }, 723 724 /** 725 * Sets the parent node 726 * @param {cc.Node} Var A pointer to the parnet node 727 */ 728 setParent:function (Var) { 729 this._parent = Var; 730 }, 731 732 /** 733 * Gets whether the anchor point will be (0,0) when you position this node. 734 * @see ignoreAnchorPointForPosition(bool) 735 * @return {Boolean} true if the anchor point will be (0,0) when you position this node. 736 */ 737 isIgnoreAnchorPointForPosition:function () { 738 return this._ignoreAnchorPointForPosition; 739 }, 740 741 /** 742 * <p> 743 * Sets whether the anchor point will be (0,0) when you position this node. <br/> 744 * <br/> 745 * This is an internal method, only used by CCLayer and CCScene. Don't call it outside framework. <br/> 746 * The default value is false, while in CCLayer and CCScene are true 747 * </p> 748 * @param {Boolean} newValue true if anchor point will be (0,0) when you position this node 749 */ 750 ignoreAnchorPointForPosition:function (newValue) { 751 if (newValue != this._ignoreAnchorPointForPosition) { 752 this._ignoreAnchorPointForPosition = newValue; 753 this.setNodeDirty(); 754 } 755 }, 756 757 /** 758 * Returns a tag that is used to identify the node easily. 759 * 760 * @return {Number} A interger that identifies the node. 761 * @example 762 * //You can set tags to node then identify them easily. 763 * // set tags 764 * node1.setTag(TAG_PLAYER); 765 * node2.setTag(TAG_MONSTER); 766 * node3.setTag(TAG_BOSS); 767 * parent.addChild(node1); 768 * parent.addChild(node2); 769 * parent.addChild(node3); 770 * // identify by tags 771 * var allChildren = parent.getChildren(); 772 * for(var i = 0; i < allChildren.length; i++){ 773 * switch(node.getTag()) { 774 * case TAG_PLAYER: 775 * break; 776 * case TAG_MONSTER: 777 * break; 778 * case TAG_BOSS: 779 * break; 780 * } 781 * } 782 */ 783 getTag:function () { 784 return this._tag; 785 }, 786 787 /** 788 * Changes the tag that is used to identify the node easily. <br/> 789 * Please refer to getTag for the sample code. 790 * @param {Number} Var A interger that indentifies the node. 791 */ 792 setTag:function (Var) { 793 this._tag = Var; 794 }, 795 796 /** 797 * <p> 798 * Returns a custom user data pointer <br/> 799 * You can set everything in UserData pointer, a data block, a structure or an object. 800 * </p> 801 * @return {object} A custom user data pointer 802 */ 803 getUserData:function () { 804 return this._userData; 805 }, 806 807 /** 808 * <p> 809 * Sets a custom user data pointer <br/> 810 * You can set everything in UserData pointer, a data block, a structure or an object, etc. 811 * </p> 812 * @warning Don't forget to relfease the memroy manually,especially before you change this data pointer, and before this node is autoreleased. 813 * @param {object} Var A custom user data 814 */ 815 setUserData:function (Var) { 816 this._userData = Var; 817 }, 818 819 /** 820 * Returns a user assigned CCObject. <br/> 821 * Similar to userData, but instead of holding a void* it holds an id 822 * @return {object} A user assigned CCObject 823 */ 824 getUserObject:function () { 825 return this._userObject; 826 }, 827 828 /** 829 * <p> 830 * Returns a user assigned CCObject <br/> 831 * Similar to UserData, but instead of holding a void* it holds an object. <br/> 832 * The UserObject will be retained once in this method, and the previous UserObject (if existed) will be relese. <br/> 833 * The UserObject will be released in CCNode's destructure. 834 * </p> 835 * @param {object} newValue A user assigned CCObject 836 */ 837 setUserObject:function (newValue) { 838 if (this._userObject != newValue) { 839 this._userObject = newValue; 840 } 841 }, 842 843 844 /** 845 * Returns the arrival order, indecates which children is added previously. 846 * @return {Number} The arrival order. 847 */ 848 getOrderOfArrival:function () { 849 return this._orderOfArrival; 850 }, 851 852 /** 853 * <p> 854 * Sets the arrival order when this node has a same ZOrder with other children. <br/> 855 * <br/> 856 * A node which called addChild subsequently will take a larger arrival order, <br/> 857 * If two children have the same Z order, the child with larger arrival order will be drawn later. 858 * </p> 859 * @warning This method is used internally for zOrder sorting, don't change this manually 860 * @param {Number} Var The arrival order. 861 */ 862 setOrderOfArrival:function (Var) { 863 this._orderOfArrival = Var; 864 }, 865 866 /** 867 * <p>Gets the CCActionManager object that is used by all actions.<br/> 868 * (IMPORTANT: If you set a new cc.ActionManager, then previously created actions are going to be removed.)</p> 869 * @see setActionManager() 870 * @return {cc.ActionManager} A CCActionManager object. 871 */ 872 getActionManager:function () { 873 if (!this._actionManager) { 874 this._actionManager = cc.Director.getInstance().getActionManager(); 875 } 876 return this._actionManager; 877 }, 878 879 /** 880 * <p>Sets the cc.ActionManager object that is used by all actions. </p> 881 * @warning If you set a new CCActionManager, then previously created actions will be removed. 882 * @param {cc.ActionManager} actionManager A CCActionManager object that is used by all actions. 883 */ 884 setActionManager:function (actionManager) { 885 if (this._actionManager != actionManager) { 886 this.stopAllActions(); 887 this._actionManager = actionManager; 888 } 889 }, 890 891 /** 892 * <p> 893 * cc.Scheduler used to schedule all "updates" and timers.<br/> 894 * IMPORTANT: If you set a new cc.Scheduler, then previously created timers/update are going to be removed. 895 * </p> 896 * @return {cc.Scheduler} A CCScheduler object. 897 */ 898 getScheduler:function () { 899 if (!this._scheduler) { 900 this._scheduler = cc.Director.getInstance().getScheduler(); 901 } 902 return this._scheduler; 903 }, 904 905 /** 906 * <p> 907 * Sets a CCScheduler object that is used to schedule all "updates" and timers. <br/> 908 * </p> 909 * @warning If you set a new CCScheduler, then previously created timers/update are going to be removed. 910 * @param scheduler A cc.Shdeduler object that is used to schedule all "update" and timers. 911 */ 912 setScheduler:function (scheduler) { 913 if (this._scheduler != scheduler) { 914 this.unscheduleAllCallbacks(); 915 this._scheduler = scheduler; 916 } 917 }, 918 919 /** 920 * Returns a "local" axis aligned bounding box of the node. <br/> 921 * The returned box is relative only to its parent. 922 * @note This method returns a temporaty variable, so it can't returns const CCRect& 923 * @const 924 * @return {cc.Rect} 925 */ 926 getBoundingBox:function () { 927 var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height); 928 return cc._RectApplyAffineTransformIn(rect, this.nodeToParentTransform()); 929 }, 930 931 /** 932 * Stops all running actions and schedulers 933 */ 934 cleanup:function () { 935 // actions 936 this.stopAllActions(); 937 this.unscheduleAllCallbacks(); 938 939 // timers 940 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.cleanup); 941 }, 942 943 /** 944 * Gets the description string. It makes debugging easier. 945 * @return {String} 946 */ 947 description:function () { 948 return "<cc.Node | Tag =" + this._tag + ">"; 949 }, 950 951 // composition: GET 952 /** 953 * Gets a child from the container given its tag 954 * @param {Number} aTag An identifier to find the child node. 955 * @return {cc.Node} a CCNode object whose tag equals to the input parameter 956 */ 957 getChildByTag:function (aTag) { 958 //cc.Assert(aTag != cc.NODE_TAG_INVALID, "Invalid tag"); 959 var __children = this._children; 960 if (__children != null) { 961 for (var i = 0; i < __children.length; i++) { 962 var node = __children[i]; 963 if (node && node._tag == aTag) 964 return node; 965 } 966 } 967 //throw "not found"; 968 return null; 969 }, 970 // composition: ADD 971 972 /** <p>"add" logic MUST only be on this method <br/> </p> 973 * 974 * <p>If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately.</p> 975 * 976 * @param {cc.Node} child A child node 977 * @param {Number} [zOrder=] Z order for drawing priority. Please refer to setZOrder(int) 978 * @param {Number} [tag=] A interger to identify the node easily. Please refer to setTag(int) 979 */ 980 addChild:function (child, zOrder, tag) { 981 if (child === this) { 982 console.warn('cc.Node.addChild: An Node can\'t be added as a child of itself.'); 983 return; 984 } 985 986 cc.Assert(child != null, "Argument must be non-nil"); 987 if (child._parent !== null) { 988 cc.Assert(child._parent === null, "child already added. It can't be added again"); 989 return; 990 } 991 992 var tmpzOrder = (zOrder != null) ? zOrder : child._zOrder; 993 child._tag = (tag != null) ? tag : child._tag; 994 this._insertChild(child, tmpzOrder); 995 child._parent = this; 996 997 if (this._running) { 998 child.onEnter(); 999 // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter 1000 if(this._isTransitionFinished) 1001 child.onEnterTransitionDidFinish(); 1002 } 1003 }, 1004 1005 // composition: REMOVE 1006 /** 1007 * Remove itself from its parent node. If cleanup is true, then also remove all actions and callbacks. <br/> 1008 * If the cleanup parameter is not passed, it will force a cleanup. <br/> 1009 * If the node orphan, then nothing happens. 1010 * @param {Boolean} cleanup true if all actions and callbacks on this node should be removed, false otherwise. 1011 * @see removeFromParentAndCleanup(bool) 1012 */ 1013 removeFromParent:function (cleanup) { 1014 if (this._parent) { 1015 if (cleanup == null) 1016 cleanup = true; 1017 this._parent.removeChild(this, cleanup); 1018 } 1019 }, 1020 1021 /** 1022 * Removes this node itself from its parent node. <br/> 1023 * If the node orphan, then nothing happens. 1024 * @deprecated 1025 * @param {Boolean} cleanup true if all actions and callbacks on this node should be removed, false otherwise. 1026 */ 1027 removeFromParentAndCleanup:function (cleanup) { 1028 cc.log("removeFromParentAndCleanup is deprecated. Use removeFromParent instead"); 1029 this.removeFromParent(cleanup); 1030 }, 1031 1032 /** <p>Removes a child from the container. It will also cleanup all running actions depending on the cleanup parameter. </p> 1033 * If the cleanup parameter is not passed, it will force a cleanup. <br/> 1034 *<p> "remove" logic MUST only be on this method <br/> 1035 * If a class wants to extend the 'removeChild' behavior it only needs <br/> 1036 * to override this method </p> 1037 * 1038 * @param {cc.Node} child The child node which will be removed. 1039 * @param {Boolean|null} [cleanup=null] true if all running actions and callbacks on the child node will be cleanup, false otherwise. 1040 */ 1041 removeChild:function (child, cleanup) { 1042 // explicit nil handling 1043 if (this._children.length === 0) 1044 return; 1045 1046 if (cleanup == null) 1047 cleanup = true; 1048 if (this._children.indexOf(child) > -1) 1049 this._detachChild(child, cleanup); 1050 1051 this.setNodeDirty(); 1052 }, 1053 1054 /** 1055 * Removes a child from the container by tag value. It will also cleanup all running actions depending on the cleanup parameter. 1056 * If the cleanup parameter is not passed, it will force a cleanup. <br/> 1057 * @param {Number} tag An integer number that identifies a child node 1058 * @param {Boolean} cleanup true if all running actions and callbacks on the child node will be cleanup, false otherwise. 1059 * @see removeChildByTag(int, bool) 1060 */ 1061 removeChildByTag:function (tag, cleanup) { 1062 cc.Assert(tag != cc.NODE_TAG_INVALID, "Invalid tag"); 1063 1064 var child = this.getChildByTag(tag); 1065 if (child == null) 1066 cc.log("cocos2d: removeChildByTag(tag = " + tag + "): child not found!"); 1067 else 1068 this.removeChild(child, cleanup); 1069 }, 1070 1071 /** 1072 * Removes all children from the container and do a cleanup all running actions depending on the cleanup parameter. 1073 * @deprecated 1074 * @param {Boolean | null } cleanup 1075 */ 1076 removeAllChildrenWithCleanup:function (cleanup) { 1077 cc.log("removeAllChildrenWithCleanup is deprecated. Use removeAllChildren instead"); 1078 this.removeAllChildren(cleanup); 1079 }, 1080 1081 /** 1082 * Removes all children from the container and do a cleanup all running actions depending on the cleanup parameter. <br/> 1083 * If the cleanup parameter is not passed, it will force a cleanup. <br/> 1084 * @param {Boolean | null } cleanup true if all running actions on all children nodes should be cleanup, false oterwise. 1085 */ 1086 removeAllChildren:function (cleanup) { 1087 // not using detachChild improves speed here 1088 var __children = this._children; 1089 if (__children != null) { 1090 if (cleanup == null) 1091 cleanup = true; 1092 for (var i = 0; i < __children.length; i++) { 1093 var node = __children[i]; 1094 if (node) { 1095 // IMPORTANT: 1096 // -1st do onExit 1097 // -2nd cleanup 1098 if (this._running) { 1099 node.onExitTransitionDidStart(); 1100 node.onExit(); 1101 } 1102 if (cleanup) 1103 node.cleanup(); 1104 // set parent nil at the end 1105 node.setParent(null); 1106 } 1107 } 1108 this._children.length = 0; 1109 } 1110 }, 1111 1112 /** 1113 * @param {cc.Node} child 1114 * @param {Boolean} doCleanup 1115 * @private 1116 */ 1117 _detachChild:function (child, doCleanup) { 1118 // IMPORTANT: 1119 // -1st do onExit 1120 // -2nd cleanup 1121 if (this._running) { 1122 child.onExitTransitionDidStart(); 1123 child.onExit(); 1124 } 1125 1126 // If you don't do cleanup, the child's actions will not get removed and the 1127 // its scheduledSelectors_ dict will not get released! 1128 if (doCleanup) 1129 child.cleanup(); 1130 1131 // set parent nil at the end 1132 child.setParent(null); 1133 1134 cc.ArrayRemoveObject(this._children, child); 1135 }, 1136 1137 /** helper used by reorderChild & add 1138 * @param {cc.Node} child 1139 * @param {Number} z 1140 * @private 1141 */ 1142 _insertChild:function (child, z) { 1143 this._reorderChildDirty = true; 1144 this._children.push(child); 1145 child._setZOrder(z); 1146 }, 1147 1148 /** Reorders a child according to a new z value. <br/> 1149 * The child MUST be already added. 1150 * @param {cc.Node} child An already added child node. It MUST be already added. 1151 * @param {Number} zOrder Z order for drawing priority. Please refer to setZOrder(int) 1152 */ 1153 reorderChild:function (child, zOrder) { 1154 cc.Assert(child != null, "Child must be non-nil"); 1155 this._reorderChildDirty = true; 1156 child.setOrderOfArrival(cc.s_globalOrderOfArrival++); 1157 child._setZOrder(zOrder); 1158 this.setNodeDirty(); 1159 }, 1160 1161 /** 1162 * <p> 1163 * Sorts the children array once before drawing, instead of every time when a child is added or reordered. <br/> 1164 * This appraoch can improves the performance massively. 1165 * </p> 1166 * @note Don't call this manually unless a child added needs to be removed in the same frame 1167 */ 1168 sortAllChildren:function () { 1169 if (this._reorderChildDirty) { 1170 var _children = this._children; 1171 var i, j, length = _children.length,tempChild; 1172 1173 // insertion sort 1174 for (i = 0; i < length; i++) { 1175 var tempItem = _children[i]; 1176 j = i - 1; 1177 tempChild = _children[j]; 1178 1179 //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller 1180 while (j >= 0 && ( tempItem._zOrder < tempChild._zOrder || 1181 ( tempItem._zOrder == tempChild._zOrder && tempItem._orderOfArrival < tempChild._orderOfArrival ))) { 1182 _children[j + 1] = tempChild; 1183 j = j - 1; 1184 tempChild = _children[j]; 1185 } 1186 _children[j + 1] = tempItem; 1187 } 1188 1189 //don't need to check children recursively, that's done in visit of each child 1190 this._reorderChildDirty = false; 1191 } 1192 }, 1193 1194 // draw 1195 /** <p>Override this method to draw your own node. <br/> 1196 * The following GL states will be enabled by default: <br/> 1197 - glEnableClientState(GL_VERTEX_ARRAY); <br/> 1198 - glEnableClientState(GL_COLOR_ARRAY); <br/> 1199 - glEnableClientState(GL_TEXTURE_COORD_ARRAY); <br/> 1200 - glEnable(GL_TEXTURE_2D); </p> 1201 1202 <p>AND YOU SHOULD NOT DISABLE THEM AFTER DRAWING YOUR NODE</p> 1203 1204 <p>But if you enable any other GL state, you should disable it after drawing your node. </p> 1205 * @param {CanvasContext} ctx 1206 */ 1207 draw:function (ctx) { 1208 //cc.Assert(0); 1209 // override me 1210 // Only use- this function to draw your staff. 1211 // DON'T draw your stuff outside this method 1212 }, 1213 1214 /** performs OpenGL view-matrix transformation of it's ancestors.<br/> 1215 * Generally the ancestors are already transformed, but in certain cases (eg: attaching a FBO) <br/> 1216 * it's necessary to transform the ancestors again. 1217 */ 1218 transformAncestors:function () { 1219 if (this._parent != null) { 1220 this._parent.transformAncestors(); 1221 this._parent.transform(); 1222 } 1223 }, 1224 1225 //scene managment 1226 /** 1227 * <p> 1228 * Event callback that is invoked every time when CCNode enters the 'stage'. <br/> 1229 * If the CCNode enters the 'stage' with a transition, this event is called when the transition starts. <br/> 1230 * During onEnter you can't access a "sister/brother" node. <br/> 1231 * If you override onEnter, you shall call its parent's one, e.g., CCNode::onEnter(). 1232 * </p> 1233 */ 1234 onEnter:function () { 1235 this._isTransitionFinished = false; 1236 this._running = true;//should be running before resumeSchedule 1237 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onEnter); 1238 this.resumeSchedulerAndActions(); 1239 }, 1240 1241 /** 1242 * <p> 1243 * Event callback that is invoked when the CCNode enters in the 'stage'. <br/> 1244 * If the CCNode enters the 'stage' with a transition, this event is called when the transition finishes. <br/> 1245 * If you override onEnterTransitionDidFinish, you shall call its parent's one, e.g. CCNode::onEnterTransitionDidFinish() 1246 * </p> 1247 */ 1248 onEnterTransitionDidFinish:function () { 1249 this._isTransitionFinished = true; 1250 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onEnterTransitionDidFinish); 1251 }, 1252 1253 /** 1254 * <p>callback that is called every time the cc.Node leaves the 'stage'. <br/> 1255 * If the cc.Node leaves the 'stage' with a transition, this callback is called when the transition starts. </p> 1256 */ 1257 onExitTransitionDidStart:function () { 1258 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onExitTransitionDidStart); 1259 }, 1260 1261 /** 1262 * <p> 1263 * callback that is called every time the cc.Node leaves the 'stage'. <br/> 1264 * If the cc.Node leaves the 'stage' with a transition, this callback is called when the transition finishes. <br/> 1265 * During onExit you can't access a sibling node. <br/> 1266 * If you override onExit, you shall call its parent's one, e.g., CCNode::onExit(). 1267 * </p> 1268 */ 1269 onExit:function () { 1270 this._running = false; 1271 this.pauseSchedulerAndActions(); 1272 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onExit); 1273 this._componentContainer.removeAll(); 1274 }, 1275 1276 // actions 1277 /** 1278 * Executes an action, and returns the action that is executed.<br/> 1279 * The node becomes the action's target. Refer to CCAction::getTarget() 1280 * @warning Starting from v0.8 actions don't retain their target anymore. 1281 * @param {cc.Action} action 1282 * @return {cc.Action} An Action pointer 1283 */ 1284 runAction:function (action) { 1285 cc.Assert(action != null, "Argument must be non-nil"); 1286 this.getActionManager().addAction(action, this, !this._running); 1287 return action; 1288 }, 1289 1290 /** 1291 * Stops and removes all actions from the running action list . 1292 */ 1293 stopAllActions:function () { 1294 this.getActionManager().removeAllActionsFromTarget(this); 1295 }, 1296 1297 /** 1298 * Stops and removes an action from the running action list. 1299 * @param {cc.Action} action An action object to be removed. 1300 */ 1301 stopAction:function (action) { 1302 this.getActionManager().removeAction(action); 1303 }, 1304 1305 /** 1306 * Removes an action from the running action list by its tag. 1307 * @param {Number} tag A tag that indicates the action to be removed. 1308 */ 1309 stopActionByTag:function (tag) { 1310 cc.Assert(tag != cc.ACTION_TAG_INVALID, "Invalid tag"); 1311 this.getActionManager().removeActionByTag(tag, this); 1312 }, 1313 1314 /** 1315 * Gets an action from the running action list by its tag. 1316 * @see setTag(int), getTag(). 1317 * @param {Number} tag 1318 * @return {cc.Action} The action object with the given tag. 1319 */ 1320 getActionByTag:function (tag) { 1321 cc.Assert(tag != cc.ACTION_TAG_INVALID, "Invalid tag"); 1322 return this.getActionManager().getActionByTag(tag, this); 1323 }, 1324 1325 /** Returns the numbers of actions that are running plus the ones that are schedule to run (actions in actionsToAdd and actions arrays).<br/> 1326 * Composable actions are counted as 1 action. Example:<br/> 1327 * If you are running 1 Sequence of 7 actions, it will return 1. <br/> 1328 * If you are running 7 Sequences of 2 actions, it will return 7. 1329 * @return {Number} The number of actions that are running plus the ones that are schedule to run 1330 */ 1331 numberOfRunningActions:function () { 1332 return this.getActionManager().numberOfRunningActionsInTarget(this); 1333 }, 1334 1335 // cc.Node - Callbacks 1336 // timers 1337 /** 1338 * schedules the "update" method. <br/> 1339 * It will use the order number 0. This method will be called every frame. <br/> 1340 * Scheduled methods with a lower order value will be called before the ones that have a higher order value.<br/> 1341 * Only one "update" method could be scheduled per node. 1342 */ 1343 scheduleUpdate:function () { 1344 this.scheduleUpdateWithPriority(0); 1345 }, 1346 1347 /** 1348 * <p> 1349 * schedules the "update" callback function with a custom priority. 1350 * This callback function will be called every frame.<br/> 1351 * Scheduled callback functions with a lower priority will be called before the ones that have a higher value.<br/> 1352 * Only one "update" callback function could be scheduled per node (You can't have 2 'update' callback functions).<br/> 1353 * </p> 1354 * @param {Number} priority 1355 */ 1356 scheduleUpdateWithPriority:function (priority) { 1357 this.getScheduler().scheduleUpdateForTarget(this, priority, !this._running); 1358 }, 1359 1360 /** 1361 * unschedules the "update" method. 1362 * @see scheduleUpdate(); 1363 */ 1364 unscheduleUpdate:function () { 1365 this.getScheduler().unscheduleUpdateForTarget(this); 1366 }, 1367 1368 /** 1369 * Schedules a custom selector. <br/> 1370 * If the selector is already scheduled, then the interval parameter will be updated without scheduling it again. 1371 * 1372 * @param {function} callback_fn A function wrapped as a selector 1373 * @param {Number} interval Tick interval in seconds. 0 means tick every frame. If interval = 0, it's recommended to use scheduleUpdate() instead. 1374 * @param {Number} repeat The selector will be excuted (repeat + 1) times, you can use kCCRepeatForever for tick infinitely. 1375 * @param {Number} delay The amount of time that the first tick will wait before execution. 1376 */ 1377 schedule:function (callback_fn, interval, repeat, delay) { 1378 interval = interval || 0; 1379 1380 cc.Assert(callback_fn, "Argument must be non-nil"); 1381 cc.Assert(interval >= 0, "Argument must be positive"); 1382 1383 repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat; 1384 delay = delay || 0; 1385 1386 this.getScheduler().scheduleCallbackForTarget(this, callback_fn, interval, repeat, delay, !this._running); 1387 }, 1388 1389 /** 1390 * Schedules a callback function that runs only once, with a delay of 0 or larger 1391 * @see schedule(SEL_SCHEDULE, float, unsigned int, float) 1392 * @param {function} callback_fn A function wrapped as a selector 1393 * @param {Number} delay The amount of time that the first tick will wait before execution. 1394 */ 1395 scheduleOnce:function (callback_fn, delay) { 1396 this.schedule(callback_fn, 0.0, 0, delay); 1397 }, 1398 1399 /** 1400 * unschedules a custom callback function. 1401 * @see schedule(SEL_SCHEDULE, float, unsigned int, float) 1402 * @param {function} callback_fn A function wrapped as a selector 1403 */ 1404 unschedule:function (callback_fn) { 1405 // explicit nil handling 1406 if (!callback_fn) 1407 return; 1408 1409 this.getScheduler().unscheduleCallbackForTarget(this, callback_fn); 1410 }, 1411 1412 /** 1413 * unschedule all scheduled callback functions: custom callback functions, and the 'update' callback function.<br/> 1414 * Actions are not affected by this method. 1415 */ 1416 unscheduleAllCallbacks:function () { 1417 this.getScheduler().unscheduleAllCallbacksForTarget(this); 1418 }, 1419 1420 /** 1421 * Resumes all scheduled selectors and actions.<br/> 1422 * This method is called internally by onEnter 1423 */ 1424 resumeSchedulerAndActions:function () { 1425 this.getScheduler().resumeTarget(this); 1426 this.getActionManager().resumeTarget(this); 1427 }, 1428 1429 /** 1430 * Pauses all scheduled selectors and actions.<br/> 1431 * This method is called internally by onExit 1432 */ 1433 pauseSchedulerAndActions:function () { 1434 this.getScheduler().pauseTarget(this); 1435 this.getActionManager().pauseTarget(this); 1436 }, 1437 1438 /** 1439 *<p> Sets the additional transform.<br/> 1440 * The additional transform will be concatenated at the end of nodeToParentTransform.<br/> 1441 * It could be used to simulate `parent-child` relationship between two nodes (e.g. one is in BatchNode, another isn't).<br/> 1442 * </p> 1443 * @example 1444 * // create a batchNode 1445 * var batch= cc.SpriteBatchNode.create("Icon-114.png"); 1446 * this.addChild(batch); 1447 * 1448 * // create two sprites, spriteA will be added to batchNode, they are using different textures. 1449 * var spriteA = cc.Sprite.createWithTexture(batch->getTexture()); 1450 * var spriteB = cc.Sprite.create("Icon-72.png"); 1451 * 1452 * batch.addChild(spriteA); 1453 * 1454 * // We can't make spriteB as spriteA's child since they use different textures. So just add it to layer. 1455 * // But we want to simulate `parent-child` relationship for these two node. 1456 * this.addChild(spriteB); 1457 * 1458 * //position 1459 * spriteA.setPosition(ccp(200, 200)); 1460 * 1461 * // Gets the spriteA's transform. 1462 * var t = spriteA.nodeToParentTransform(); 1463 * 1464 * // Sets the additional transform to spriteB, spriteB's postion will based on its pseudo parent i.e. spriteA. 1465 * spriteB.setAdditionalTransform(t); 1466 * 1467 * //scale 1468 * spriteA.setScale(2); 1469 * 1470 * // Gets the spriteA's transform. 1471 * t = spriteA.nodeToParentTransform(); 1472 * 1473 * // Sets the additional transform to spriteB, spriteB's scale will based on its pseudo parent i.e. spriteA. 1474 * spriteB.setAdditionalTransform(t); 1475 * 1476 * //rotation 1477 * spriteA.setRotation(20); 1478 * 1479 * // Gets the spriteA's transform. 1480 * t = spriteA.nodeToParentTransform(); 1481 * 1482 * // Sets the additional transform to spriteB, spriteB's rotation will based on its pseudo parent i.e. spriteA. 1483 * spriteB.setAdditionalTransform(t); 1484 */ 1485 setAdditionalTransform:function (additionalTransform) { 1486 this._additionalTransform = additionalTransform; 1487 this._transformDirty = true; 1488 this._additionalTransformDirty = true; 1489 }, 1490 1491 /** 1492 * Returns the matrix that transform parent's space coordinates to the node's (local) space coordinates.<br/> 1493 * The matrix is in Pixels. 1494 * @return {cc.AffineTransform} 1495 */ 1496 parentToNodeTransform:function () { 1497 if (this._inverseDirty) { 1498 this._inverse = cc.AffineTransformInvert(this.nodeToParentTransform()); 1499 this._inverseDirty = false; 1500 } 1501 return this._inverse; 1502 }, 1503 1504 /** 1505 * Returns the world affine transform matrix. The matrix is in Pixels. 1506 * @return {cc.AffineTransform} 1507 */ 1508 nodeToWorldTransform:function () { 1509 var t = this.nodeToParentTransform(); 1510 for (var p = this._parent; p != null; p = p.getParent()) 1511 t = cc.AffineTransformConcat(t, p.nodeToParentTransform()); 1512 return t; 1513 }, 1514 1515 /** 1516 * Returns the inverse world affine transform matrix. The matrix is in Pixels. 1517 * @return {cc.AffineTransform} 1518 */ 1519 worldToNodeTransform:function () { 1520 return cc.AffineTransformInvert(this.nodeToWorldTransform()); 1521 }, 1522 1523 /** 1524 * Converts a Point to node (local) space coordinates. The result is in Points. 1525 * @param {cc.Point} worldPoint 1526 * @return {cc.Point} 1527 */ 1528 convertToNodeSpace:function (worldPoint) { 1529 return cc.PointApplyAffineTransform(worldPoint, this.worldToNodeTransform()); 1530 }, 1531 1532 /** 1533 * Converts a Point to world space coordinates. The result is in Points. 1534 * @param {cc.Point} nodePoint 1535 * @return {cc.Point} 1536 */ 1537 convertToWorldSpace:function (nodePoint) { 1538 return cc.PointApplyAffineTransform(nodePoint, this.nodeToWorldTransform()); 1539 }, 1540 1541 /** 1542 * Converts a Point to node (local) space coordinates. The result is in Points.<br/> 1543 * treating the returned/received node point as anchor relative. 1544 * @param {cc.Point} worldPoint 1545 * @return {cc.Point} 1546 */ 1547 convertToNodeSpaceAR:function (worldPoint) { 1548 return cc.pSub(this.convertToNodeSpace(worldPoint), this._anchorPointInPoints); 1549 }, 1550 1551 /** 1552 * Converts a local Point to world space coordinates.The result is in Points.<br/> 1553 * treating the returned/received node point as anchor relative. 1554 * @param {cc.Point} nodePoint 1555 * @return {cc.Point} 1556 */ 1557 convertToWorldSpaceAR:function (nodePoint) { 1558 var pt = cc.pAdd(nodePoint, this._anchorPointInPoints); 1559 return this.convertToWorldSpace(pt); 1560 }, 1561 1562 _convertToWindowSpace:function (nodePoint) { 1563 var worldPoint = this.convertToWorldSpace(nodePoint); 1564 return cc.Director.getInstance().convertToUI(worldPoint); 1565 }, 1566 1567 /** convenience methods which take a cc.Touch instead of cc.Point 1568 * @param {cc.Touch} touch 1569 * @return {cc.Point} 1570 */ 1571 convertTouchToNodeSpace:function (touch) { 1572 var point = touch.getLocation(); 1573 //TODO This point needn't convert to GL in HTML5 1574 //point = cc.Director.getInstance().convertToGL(point); 1575 return this.convertToNodeSpace(point); 1576 }, 1577 1578 /** 1579 * converts a cc.Touch (world coordinates) into a local coordiante. This method is AR (Anchor Relative). 1580 * @param {cc.Touch}touch 1581 * @return {cc.Point} 1582 */ 1583 convertTouchToNodeSpaceAR:function (touch) { 1584 var point = touch.getLocation(); 1585 point = cc.Director.getInstance().convertToGL(point); 1586 return this.convertToNodeSpaceAR(point); 1587 }, 1588 1589 /** 1590 * Update will be called automatically every frame if "scheduleUpdate" is called, and the node is "live" <br/> 1591 * (override me) 1592 * @param {Number} dt deltaTime 1593 */ 1594 update:function (dt) { 1595 if(this._componentContainer && !this._componentContainer.isEmpty()) 1596 this._componentContainer.visit(dt); 1597 }, 1598 1599 /** 1600 * <p> 1601 * Calls children's updateTransform() method recursively. <br/> 1602 * <br/> 1603 * This method is moved from CCSprite, so it's no longer specific to CCSprite. <br/> 1604 * As the result, you apply CCSpriteBatchNode's optimization on your customed CCNode. <br/> 1605 * e.g., batchNode->addChild(myCustomNode), while you can only addChild(sprite) before. 1606 * </p> 1607 */ 1608 updateTransform:function () { 1609 // Recursively iterate over children 1610 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform); 1611 }, 1612 1613 /** 1614 * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB, 1615 * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. 1616 * This is a hack, and should be removed once JSB fixes the retain/release bug 1617 */ 1618 retain:function () { 1619 }, 1620 release:function () { 1621 }, 1622 1623 /** 1624 * gets a component by its name 1625 * @param {String} name 1626 * @return {cc.Component} gets a component by its name 1627 */ 1628 getComponent:function(name){ 1629 return this._componentContainer.getComponent(name); 1630 }, 1631 1632 /** 1633 * adds a component 1634 * @param {cc.Component} component 1635 */ 1636 addComponent:function(component){ 1637 this._componentContainer.add(component); 1638 }, 1639 1640 /** 1641 * removes a component by its name 1642 * @param {String} name 1643 */ 1644 removeComponent:function(name){ 1645 return this._componentContainer.remove(name); 1646 }, 1647 1648 /** 1649 * removes all components 1650 */ 1651 removeAllComponents:function(){ 1652 this._componentContainer.removeAll(); 1653 }, 1654 1655 _transform4x4:null, 1656 _stackMatrix:null, 1657 _glServerState:null, 1658 _camera:null, 1659 _grid:null, 1660 1661 /** 1662 * Constructor 1663 */ 1664 ctor: null, 1665 1666 _ctorForCanvas: function () { 1667 this._initNode(); 1668 }, 1669 1670 _ctorForWebGL: function () { 1671 this._initNode(); 1672 1673 //WebGL 1674 var mat4 = new cc.kmMat4(); 1675 mat4.mat[2] = mat4.mat[3] = mat4.mat[6] = mat4.mat[7] = mat4.mat[8] = mat4.mat[9] = mat4.mat[11] = mat4.mat[14] = 0.0; 1676 mat4.mat[10] = mat4.mat[15] = 1.0; 1677 this._transform4x4 = mat4; 1678 this._glServerState = 0; 1679 this._stackMatrix = new cc.kmMat4(); 1680 }, 1681 1682 /** 1683 * recursive method that visit its children and draw them 1684 * @param {CanvasRenderingContext2D|WebGLRenderingContext} ctx 1685 */ 1686 visit:null, 1687 1688 _visitForCanvas:function (ctx) { 1689 // quick return if not visible 1690 if (!this._visible) 1691 return; 1692 1693 //visit for canvas 1694 var context = ctx || cc.renderContext, i; 1695 var children = this._children,child; 1696 context.save(); 1697 this.transform(context); 1698 var len = children.length; 1699 if (len > 0) { 1700 this.sortAllChildren(); 1701 // draw children zOrder < 0 1702 for (i = 0; i < len; i++) { 1703 child = children[i]; 1704 if (child._zOrder < 0) 1705 child.visit(context); 1706 else 1707 break; 1708 } 1709 this.draw(context); 1710 for (; i < len; i++) { 1711 children[i].visit(context); 1712 } 1713 } else 1714 this.draw(context); 1715 1716 this._orderOfArrival = 0; 1717 context.restore(); 1718 }, 1719 1720 _visitForWebGL: function(){ 1721 // quick return if not visible 1722 if (!this._visible) 1723 return; 1724 var context = cc.renderContext, i, currentStack = cc.current_stack; 1725 1726 //cc.kmGLPushMatrixWitMat4(this._stackMatrix); 1727 //optimize performance for javascript 1728 currentStack.stack.push(currentStack.top); 1729 cc.kmMat4Assign(this._stackMatrix, currentStack.top); 1730 currentStack.top = this._stackMatrix; 1731 1732 var locGrid = this._grid; 1733 if (locGrid && locGrid._active) 1734 locGrid.beforeDraw(); 1735 1736 this.transform(); 1737 1738 var locChildren = this._children; 1739 if (locChildren && locChildren.length > 0) { 1740 var childLen = locChildren.length; 1741 this.sortAllChildren(); 1742 // draw children zOrder < 0 1743 for (i = 0; i < childLen; i++) { 1744 if (locChildren[i] && locChildren[i]._zOrder < 0) 1745 locChildren[i].visit(); 1746 else 1747 break; 1748 } 1749 this.draw(context); 1750 // draw children zOrder >= 0 1751 for (; i < childLen; i++) { 1752 if (locChildren[i]) { 1753 locChildren[i].visit(); 1754 } 1755 } 1756 } else 1757 this.draw(context); 1758 1759 this._orderOfArrival = 0; 1760 if (locGrid && locGrid._active) 1761 locGrid.afterDraw(this); 1762 1763 //cc.kmGLPopMatrix(); 1764 //optimize performance for javascript 1765 currentStack.top = currentStack.stack.pop(); 1766 }, 1767 1768 /** 1769 * Performs OpenGL view-matrix transformation based on position, scale, rotation and other attributes. 1770 */ 1771 transform:null, 1772 1773 _transformForCanvas: function (ctx) { 1774 // transform for canvas 1775 var context = ctx || cc.renderContext; 1776 var t = this.nodeToParentTransform(); 1777 context.transform(t.a, t.c, t.b, t.d, t.tx, -t.ty); 1778 }, 1779 1780 _transformForWebGL: function () { 1781 //optimize performance for javascript 1782 var t4x4 = this._transform4x4, topMat4 = cc.current_stack.top; 1783 1784 // Convert 3x3 into 4x4 matrix 1785 //cc.CGAffineToGL(this.nodeToParentTransform(), this._transform4x4.mat); 1786 var trans = this.nodeToParentTransform(); 1787 var t4x4Mat = t4x4.mat; 1788 t4x4Mat[0] = trans.a; 1789 t4x4Mat[4] = trans.c; 1790 t4x4Mat[12] = trans.tx; 1791 t4x4Mat[1] = trans.b; 1792 t4x4Mat[5] = trans.d; 1793 t4x4Mat[13] = trans.ty; 1794 1795 // Update Z vertex manually 1796 //this._transform4x4.mat[14] = this._vertexZ; 1797 t4x4Mat[14] = this._vertexZ; 1798 1799 //optimize performance for Javascript 1800 cc.kmMat4Multiply(topMat4, topMat4, t4x4); // = cc.kmGLMultMatrix(this._transform4x4); 1801 1802 // XXX: Expensive calls. Camera should be integrated into the cached affine matrix 1803 if (this._camera != null && !(this._grid != null && this._grid.isActive())) { 1804 var apx = this._anchorPointInPoints.x, apy = this._anchorPointInPoints.y; 1805 var translate = (apx !== 0.0 || apy !== 0.0); 1806 if (translate){ 1807 cc.kmGLTranslatef(cc.RENDER_IN_SUBPIXEL(apx), cc.RENDER_IN_SUBPIXEL(apy), 0); 1808 this._camera.locate(); 1809 cc.kmGLTranslatef(cc.RENDER_IN_SUBPIXEL(-apx), cc.RENDER_IN_SUBPIXEL(-apy), 0); 1810 } else { 1811 this._camera.locate(); 1812 } 1813 } 1814 }, 1815 1816 /** Returns the matrix that transform the node's (local) space coordinates into the parent's space coordinates.<br/> 1817 * The matrix is in Pixels. 1818 * @return {cc.AffineTransform} 1819 */ 1820 nodeToParentTransform: null, 1821 1822 _nodeToParentTransformForCanvas:function () { 1823 if (!this._transform) 1824 this._transform = {a:1, b:0, c:0, d:1, tx:0, ty:0}; 1825 if (this._transformDirty) { 1826 var t = this._transform;// quick reference 1827 // base position 1828 t.tx = this._position.x; 1829 t.ty = this._position.y; 1830 1831 // rotation Cos and Sin 1832 var Cos = 1, Sin = 0; 1833 if (this._rotationX) { 1834 Cos = Math.cos(this._rotationRadiansX); 1835 Sin = Math.sin(this._rotationRadiansX); 1836 } 1837 1838 // base abcd 1839 t.a = t.d = Cos; 1840 t.b = -Sin; 1841 t.c = Sin; 1842 1843 var lScaleX = this._scaleX, lScaleY = this._scaleY; 1844 var appX = this._anchorPointInPoints.x, appY = this._anchorPointInPoints.y; 1845 1846 // Firefox on Vista and XP crashes 1847 // GPU thread in case of scale(0.0, 0.0) 1848 var sx = (lScaleX < 0.000001 && lScaleX > -0.000001)? 0.000001 : lScaleX, 1849 sy = (lScaleY < 0.000001 && lScaleY > -0.000001)? 0.000001 : lScaleY; 1850 1851 // skew 1852 if (this._skewX || this._skewY) { 1853 // offset the anchorpoint 1854 var skx = Math.tan(-this._skewX * Math.PI / 180); 1855 var sky = Math.tan(-this._skewY * Math.PI / 180); 1856 var xx = appY * skx * sx; 1857 var yy = appX * sky * sy; 1858 t.a = Cos + -Sin * sky; 1859 t.b = Cos * skx + -Sin; 1860 t.c = Sin + Cos * sky; 1861 t.d = Sin * skx + Cos; 1862 t.tx += Cos * xx + -Sin * yy; 1863 t.ty += Sin * xx + Cos * yy; 1864 } 1865 1866 // scale 1867 if (lScaleX !== 1 || lScaleY !== 1) { 1868 t.a *= sx; 1869 t.c *= sx; 1870 t.b *= sy; 1871 t.d *= sy; 1872 } 1873 1874 // adjust anchorPoint 1875 t.tx += Cos * -appX * sx + -Sin * appY * sy; 1876 t.ty -= Sin * -appX * sx + Cos * appY * sy; 1877 1878 // if ignore anchorPoint 1879 if (this._ignoreAnchorPointForPosition) { 1880 t.tx += appX; 1881 t.ty += appY; 1882 } 1883 1884 if (this._additionalTransformDirty) { 1885 this._transform = cc.AffineTransformConcat(this._transform, this._additionalTransform); 1886 this._additionalTransformDirty = false; 1887 } 1888 1889 this._transformDirty = false; 1890 } 1891 return this._transform; 1892 }, 1893 1894 _nodeToParentTransformForWebGL:function () { 1895 if (this._transformDirty) { 1896 // Translate values 1897 var x = this._position.x; 1898 var y = this._position.y; 1899 var apx = this._anchorPointInPoints.x, napx = -apx; 1900 var apy = this._anchorPointInPoints.y, napy = -apy; 1901 var scx = this._scaleX, scy = this._scaleY; 1902 1903 if (this._ignoreAnchorPointForPosition) { 1904 x += apx; 1905 y += apy; 1906 } 1907 1908 // Rotation values 1909 // Change rotation code to handle X and Y 1910 // If we skew with the exact same value for both x and y then we're simply just rotating 1911 var cx = 1, sx = 0, cy = 1, sy = 0; 1912 if (this._rotationX !== 0 || this._rotationY !== 0) { 1913 cx = Math.cos(-this._rotationRadiansX); 1914 sx = Math.sin(-this._rotationRadiansX); 1915 cy = Math.cos(-this._rotationRadiansY); 1916 sy = Math.sin(-this._rotationRadiansY); 1917 } 1918 var needsSkewMatrix = ( this._skewX || this._skewY ); 1919 1920 // optimization: 1921 // inline anchor point calculation if skew is not needed 1922 // Adjusted transform calculation for rotational skew 1923 if (!needsSkewMatrix && (apx !== 0 || apy !== 0)) { 1924 x += cy * napx * scx + -sx * napy * scy; 1925 y += sy * napx * scx + cx * napy * scy; 1926 } 1927 1928 // Build Transform Matrix 1929 // Adjusted transform calculation for rotational skew 1930 var t = {a: cy * scx, b: sy * scx, c: -sx * scy, d: cx * scy, tx: x, ty: y}; 1931 1932 // XXX: Try to inline skew 1933 // If skew is needed, apply skew and then anchor point 1934 if (needsSkewMatrix) { 1935 t = cc.AffineTransformConcat({a: 1.0, b: Math.tan(cc.DEGREES_TO_RADIANS(this._skewY)), 1936 c: Math.tan(cc.DEGREES_TO_RADIANS(this._skewX)), d: 1.0, tx: 0.0, ty: 0.0}, t); 1937 1938 // adjust anchor point 1939 if (apx !== 0 || apy !== 0) 1940 t = cc.AffineTransformTranslate(t, napx, napy); 1941 } 1942 1943 if (this._additionalTransformDirty) { 1944 t = cc.AffineTransformConcat(t, this._additionalTransform); 1945 this._additionalTransformDirty = false; 1946 } 1947 this._transform = t; 1948 this._transformDirty = false; 1949 } 1950 return this._transform; 1951 }, 1952 1953 _setNodeDirtyForCache:function () { 1954 this._cacheDirty = true; 1955 if (this._parent) { 1956 this._parent._setNodeDirtyForCache(); 1957 } 1958 }, 1959 1960 /** 1961 * Returns a camera object that lets you move the node using a gluLookAt 1962 * @return {cc.Camera} A CCCamera object that lets you move the node using a gluLookAt 1963 * @example 1964 * var camera = node.getCamera(); 1965 * camera.setEye(0, 0, 415/2); 1966 * camera.setCenter(0, 0, 0); 1967 */ 1968 getCamera:function () { 1969 if (!this._camera) { 1970 this._camera = new cc.Camera(); 1971 } 1972 return this._camera; 1973 }, 1974 1975 /** 1976 * Returns a grid object that is used when applying effects 1977 * @return {cc.GridBase} A CCGrid object that is used when applying effects 1978 */ 1979 getGrid:function () { 1980 return this._grid; 1981 }, 1982 1983 /** 1984 * Changes a grid object that is used when applying effects 1985 * @param {cc.GridBase} grid A CCGrid object that is used when applying effects 1986 */ 1987 setGrid:function (grid) { 1988 this._grid = grid; 1989 }, 1990 1991 /** 1992 * Return the shader program currently used for this node 1993 * @return {cc.GLProgram} The shader program currelty used for this node 1994 */ 1995 getShaderProgram:function () { 1996 return this._shaderProgram; 1997 }, 1998 1999 /** 2000 * <p> 2001 * Sets the shader program for this node 2002 * 2003 * Since v2.0, each rendering node must set its shader program. 2004 * It should be set in initialize phase. 2005 * </p> 2006 * @param {cc.GLProgram} newShaderProgram The shader program which fetchs from CCShaderCache. 2007 * @example 2008 * node.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_TEXTURECOLOR)); 2009 */ 2010 setShaderProgram:function (newShaderProgram) { 2011 this._shaderProgram = newShaderProgram; 2012 }, 2013 2014 /** 2015 * Returns the state of OpenGL server side. 2016 * @return {Number} The state of OpenGL server side. 2017 */ 2018 getGLServerState:function () { 2019 return this._glServerState; 2020 }, 2021 2022 /** 2023 * Sets the state of OpenGL server side. 2024 * @param {Number} state The state of OpenGL server side. 2025 */ 2026 setGLServerState:function (state) { 2027 this._glServerState = state; 2028 }, 2029 2030 /** returns a "world" axis aligned bounding box of the node. <br/> 2031 * @return {cc.Rect} 2032 */ 2033 getBoundingBoxToWorld:function () { 2034 var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height); 2035 rect = cc.RectApplyAffineTransform(rect, this.nodeToWorldTransform()); 2036 rect = cc.rect(0 | rect.x - 4, 0 | rect.y - 4, 0 | rect.width + 8, 0 | rect.height + 8); 2037 //query child's BoundingBox 2038 if (!this._children) 2039 return rect; 2040 2041 var locChildren = this._children; 2042 for (var i = 0; i < locChildren.length; i++) { 2043 var child = locChildren[i]; 2044 if (child && child._visible) { 2045 var childRect = child.getBoundingBoxToWorld(); 2046 if (childRect) 2047 rect = cc.rectUnion(rect, childRect); 2048 } 2049 } 2050 return rect; 2051 } 2052 }); 2053 2054 if(cc.Browser.supportWebGL){ 2055 //WebGL 2056 cc.Node.prototype.ctor = cc.Node.prototype._ctorForWebGL; 2057 cc.Node.prototype.setNodeDirty = cc.Node.prototype._setNodeDirtyForWebGL; 2058 cc.Node.prototype.visit = cc.Node.prototype._visitForWebGL; 2059 cc.Node.prototype.transform = cc.Node.prototype._transformForWebGL; 2060 cc.Node.prototype.nodeToParentTransform = cc.Node.prototype._nodeToParentTransformForWebGL; 2061 }else{ 2062 //Canvas 2063 cc.Node.prototype.ctor = cc.Node.prototype._ctorForCanvas; 2064 cc.Node.prototype.setNodeDirty = cc.Node.prototype._setNodeDirtyForCanvas; 2065 cc.Node.prototype.visit = cc.Node.prototype._visitForCanvas; 2066 cc.Node.prototype.transform = cc.Node.prototype._transformForCanvas; 2067 cc.Node.prototype.nodeToParentTransform = cc.Node.prototype._nodeToParentTransformForCanvas; 2068 } 2069 2070 /** 2071 * allocates and initializes a node. 2072 * @constructs 2073 * @return {cc.Node} 2074 * @example 2075 * // example 2076 * var node = cc.Node.create(); 2077 */ 2078 cc.Node.create = function () { 2079 return new cc.Node(); 2080 }; 2081 2082 /** 2083 * cc.Node's state callback type 2084 * @constant 2085 * @type Number 2086 */ 2087 cc.Node.StateCallbackType = {onEnter:1, onExit:2, cleanup:3, onEnterTransitionDidFinish:4, updateTransform:5, onExitTransitionDidStart:6, sortAllChildren:7}; 2088 2089 /** 2090 * <p> 2091 * cc.NodeRGBA is a subclass of cc.Node that implements the CCRGBAProtocol protocol. <br/> 2092 * <br/> 2093 * All features from CCNode are valid, plus the following new features: <br/> 2094 * - opacity <br/> 2095 * - RGB colors <br/> 2096 * <br/> 2097 * Opacity/Color propagates into children that conform to the CCRGBAProtocol if cascadeOpacity/cascadeColor is enabled. <br/> 2098 * </p> 2099 * 2100 * @class 2101 * @extends cc.Node 2102 */ 2103 cc.NodeRGBA = cc.Node.extend(/** @lends cc.NodeRGBA# */{ 2104 RGBAProtocol:true, 2105 _displayedOpacity:255, 2106 _realOpacity:255, 2107 _displayedColor:null, 2108 _realColor:null, 2109 _cascadeColorEnabled:false, 2110 _cascadeOpacityEnabled:false, 2111 2112 ctor:function(){ 2113 cc.Node.prototype.ctor.call(this); 2114 this._displayedOpacity = 255; 2115 this._realOpacity = 255; 2116 this._displayedColor = cc.WHITE; 2117 this._realColor = cc.WHITE; 2118 this._cascadeColorEnabled = false; 2119 this._cascadeOpacityEnabled = false; 2120 }, 2121 2122 getOpacity:function(){ 2123 return this._realOpacity; 2124 }, 2125 2126 getDisplayedOpacity:function(){ 2127 return this._displayedOpacity; 2128 }, 2129 2130 setOpacity:function(opacity){ 2131 this._displayedOpacity = this._realOpacity = opacity; 2132 2133 if (this._cascadeOpacityEnabled) { 2134 var parentOpacity = 255, locParent = this._parent; 2135 if (locParent && locParent.RGBAProtocol && locParent.isCascadeOpacityEnabled()) 2136 parentOpacity = locParent.getDisplayedOpacity(); 2137 this.updateDisplayedOpacity(parentOpacity); 2138 } 2139 }, 2140 2141 updateDisplayedOpacity:function(parentOpacity){ 2142 this._displayedOpacity = this._realOpacity * parentOpacity/255.0; 2143 if (this._cascadeOpacityEnabled) { 2144 var selChildren = this._children; 2145 for(var i = 0; i< selChildren.length;i++){ 2146 var item = selChildren[i]; 2147 if(item && item.RGBAProtocol) 2148 item.updateDisplayedOpacity(this._displayedOpacity); 2149 } 2150 } 2151 }, 2152 2153 isCascadeOpacityEnabled:function(){ 2154 return this._cascadeOpacityEnabled; 2155 }, 2156 2157 setCascadeOpacityEnabled:function(cascadeOpacityEnabled){ 2158 this._cascadeOpacityEnabled = cascadeOpacityEnabled; 2159 }, 2160 2161 getColor:function(){ 2162 var locRealColor = this._realColor; 2163 return new cc.Color3B(locRealColor.r, locRealColor.g, locRealColor.b); 2164 }, 2165 2166 getDisplayedColor:function(){ 2167 return this._displayedColor; 2168 }, 2169 2170 setColor:function(color){ 2171 var locDisplayedColor = this._displayedColor, locRealColor = this._realColor; 2172 locDisplayedColor.r = color.r; 2173 locDisplayedColor.g = color.g; 2174 locDisplayedColor.b = color.b; 2175 locRealColor.r = color.r; 2176 locRealColor.g = color.g; 2177 locRealColor.b = color.b; 2178 2179 if (this._cascadeColorEnabled) { 2180 var parentColor = cc.white(); 2181 var locParent = this._parent; 2182 if (locParent && locParent.RGBAProtocol && locParent.isCascadeColorEnabled()) 2183 parentColor = locParent.getDisplayedColor(); 2184 this.updateDisplayedColor(parentColor); 2185 } 2186 }, 2187 2188 updateDisplayedColor:function(parentColor){ 2189 var locDispColor = this._displayedColor, locRealColor = this._realColor; 2190 locDispColor.r = locRealColor.r * parentColor.r/255.0; 2191 locDispColor.g = locRealColor.g * parentColor.g/255.0; 2192 locDispColor.b = locRealColor.b * parentColor.b/255.0; 2193 2194 if (this._cascadeColorEnabled){ 2195 var selChildren = this._children; 2196 for(var i = 0; i< selChildren.length;i++){ 2197 var item = selChildren[i]; 2198 if(item && item.RGBAProtocol) 2199 item.updateDisplayedColor(locDispColor); 2200 } 2201 } 2202 }, 2203 2204 isCascadeColorEnabled:function(){ 2205 return this._cascadeColorEnabled; 2206 }, 2207 2208 setCascadeColorEnabled:function(cascadeColorEnabled){ 2209 this._cascadeColorEnabled = cascadeColorEnabled; 2210 }, 2211 2212 setOpacityModifyRGB:function(opacityValue){}, 2213 2214 isOpacityModifyRGB:function(){ 2215 return false; 2216 } 2217 }); 2218