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