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