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