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