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