1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 /** 28 * Default Node tag 29 * @constant 30 * @type Number 31 */ 32 cc.NODE_TAG_INVALID = -1; 33 /** 34 * Node on enter 35 * @constant 36 */ 37 cc.NODE_ON_ENTER = null; 38 /** 39 * Node on exit 40 * @constant 41 */ 42 cc.NODE_ON_EXIT = null; 43 44 /** 45 * save the context 46 * @function 47 */ 48 cc.saveContext = function () { 49 if (cc.renderContextType == cc.CANVAS) { 50 cc.renderContext.save(); 51 } else { 52 //glPushMatrix(); 53 } 54 }; 55 56 /** 57 * restore the context 58 * @function 59 */ 60 cc.restoreContext = function () { 61 if (cc.renderContextType == cc.CANVAS) { 62 cc.renderContext.restore(); 63 } else { 64 //glPopMatrix(); 65 } 66 }; 67 68 /** 69 * 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. 70 * @type Number 71 */ 72 cc.s_globalOrderOfArrival = 1; 73 74 75 /** <p>cc.Node is the main element. Anything thats gets drawn or contains things that get drawn is a cc.Node.<br/> 76 The most popular cc.Nodes are: cc.Scene, cc.Layer, cc.Sprite, cc.Menu.<br/></p> 77 78 <p>The main features of a cc.Node are: <br/> 79 - They can contain other cc.Node nodes (addChild, getChildByTag, removeChild, etc) <br/> 80 - They can schedule periodic callback (schedule, unschedule, etc) <br/> 81 - They can execute actions (runAction, stopAction, etc) <br/></p> 82 83 <p>Some cc.Node nodes provide extra functionality for them or their children.</p> 84 85 <p>Subclassing a cc.Node usually means (one/all) of: <br/> 86 - overriding init to initialize resources and schedule callbacks <br/> 87 - create callbacks to handle the advancement of time <br/> 88 - overriding draw to render the node <br/></p> 89 90 <p>Features of cc.Node: <br/> 91 - position <br/> 92 - scale (x, y) <br/> 93 - rotation (in degrees, clockwise) <br/> 94 - cc.Camera (an interface to gluLookAt ) <br/> 95 - cc.GridBase (to do mesh transformations) <br/> 96 - anchor point<br/> 97 - size <br/> 98 - visible<br/> 99 - z-order <br/> 100 - openGL z position <br/></P> 101 102 <p> Default values: <br/> 103 - rotation: 0 <br/> 104 - position: (x=0,y=0) <br/> 105 - scale: (x=1,y=1) <br/> 106 - contentSize: (x=0,y=0)<br/> 107 - anchorPoint: (x=0,y=0)<br/></p> 108 109 <p> Limitations:<br/> 110 - A cc.Node is a "void" object. It doesn't have a texture <br/></P> 111 112 <p>Order in transformations with grid disabled <br/> 113 -# The node will be translated (position) <br/> 114 -# The node will be rotated (rotation)<br/> 115 -# The node will be scaled (scale) <br/> 116 -# The node will be moved according to the camera values (camera) <br/></p> 117 118 <p>Order in transformations with grid enabled<br/> 119 -# The node will be translated (position)<br/> 120 -# The node will be rotated (rotation) <br/> 121 -# The node will be scaled (scale) <br/> 122 -# The grid will capture the screen <br/> 123 -# The node will be moved according to the camera values (camera) <br/> 124 -# The grid will render the captured screen <br/></P> 125 126 <p>Camera: <br/> 127 - Each node has a camera. By default it points to the center of the cc.Node.</P> 128 * @class 129 * @extends cc.Class 130 * @example 131 * // example 132 * cc.Sprite = cc.Node.extend({}); 133 * cc.Sprite.initWithImage = function(){ 134 * }; 135 */ 136 cc.Node = cc.Class.extend(/** @lends cc.Node# */{ 137 _zOrder:0, 138 _vertexZ:0.0, 139 _rotation:0.0, 140 _scaleX:1.0, 141 _scaleY:1.0, 142 _position:cc.p(0, 0), 143 _skewX:0.0, 144 _skewY:0.0, 145 // children (lazy allocs), 146 _children:null, 147 // lazy alloc, 148 _camera:null, 149 _grid:null, 150 _visible:true, 151 _anchorPoint:cc.p(0, 0), 152 _anchorPointInPoints:cc.p(0, 0), 153 _contentSize:cc.SizeZero(), 154 _running:false, 155 _parent:null, 156 // "whole screen" objects. like Scenes and Layers, should set _ignoreAnchorPointForPosition to true 157 _ignoreAnchorPointForPosition:false, 158 _tag:cc.NODE_TAG_INVALID, 159 // userData is always inited as nil 160 _userData:null, 161 _userObject:null, 162 _transformDirty:true, 163 _inverseDirty:true, 164 _cacheDirty:true, 165 _transformGLDirty:null, 166 _transform:null, 167 _inverse:null, 168 //since 2.0 api 169 _reorderChildDirty:false, 170 _shaderProgram:null, 171 _orderOfArrival:0, 172 _glServerState:null, 173 _actionManager:null, 174 _scheduler:null, 175 176 _initializedNode:false, 177 178 /** 179 * Constructor 180 */ 181 ctor:function () { 182 this._initNode(); 183 }, 184 185 _initNode:function () { 186 if (cc.NODE_TRANSFORM_USING_AFFINE_MATRIX) { 187 this._transformGLDirty = true; 188 } 189 this._anchorPoint = cc.p(0, 0); 190 this._anchorPointInPoints = cc.p(0, 0); 191 this._contentSize = cc.size(0, 0); 192 this._position = cc.p(0, 0); 193 194 var director = cc.Director.getInstance(); 195 this._actionManager = director.getActionManager(); 196 this.getActionManager = function () { 197 return this._actionManager; 198 }; 199 this._scheduler = director.getScheduler(); 200 this.getScheduler = function () { 201 return this._scheduler; 202 }; 203 this._initializedNode = true; 204 }, 205 206 init:function () { 207 if (this._initializedNode === false) 208 this._initNode(); 209 return true; 210 }, 211 212 /** 213 * @param {Array} array 214 * @param {cc.Node.StateCallbackType} function Type 215 * @private 216 */ 217 _arrayMakeObjectsPerformSelector:function (array, callbackType) { 218 if (!array || array.length == 0) 219 return; 220 221 var i; 222 switch (callbackType) { 223 case cc.Node.StateCallbackType.onEnter: 224 for (i = 0; i < array.length; i++) { 225 if (array[i]) 226 array[i].onEnter(); 227 } 228 break; 229 case cc.Node.StateCallbackType.onExit: 230 for (i = 0; i < array.length; i++) { 231 if (array[i]) 232 array[i].onExit(); 233 } 234 break; 235 case cc.Node.StateCallbackType.onEnterTransitionDidFinish: 236 for (i = 0; i < array.length; i++) { 237 if (array[i]) 238 array[i].onEnterTransitionDidFinish(); 239 } 240 break; 241 case cc.Node.StateCallbackType.cleanup: 242 for (i = 0; i < array.length; i++) { 243 if (array[i]) 244 array[i].cleanup(); 245 } 246 break; 247 case cc.Node.StateCallbackType.updateTransform: 248 for (i = 0; i < array.length; i++) { 249 if (array[i]) 250 array[i].updateTransform(); 251 } 252 break; 253 case cc.Node.StateCallbackType.onExitTransitionDidStart: 254 for (i = 0; i < array.length; i++) { 255 if (array[i]) 256 array[i].onExitTransitionDidStart(); 257 } 258 break; 259 case cc.Node.StateCallbackType.sortAllChildren: 260 for (i = 0; i < array.length; i++) { 261 if (array[i]) 262 array[i].sortAllChildren(); 263 } 264 break; 265 default : 266 throw "Unknown callback function"; 267 break; 268 } 269 }, 270 271 /** 272 * @param {cc.Rect} rect 273 * @private 274 */ 275 _addDirtyRegionToDirector:function (rect) { 276 //if (!cc.firstRun) { 277 //cc.Director.getInstance().addRegionToDirtyRegion(rect); 278 //} 279 }, 280 281 _isInDirtyRegion:function () { 282 //if (!cc.firstRun) { 283 // return cc.Director.getInstance().rectIsInDirtyRegion(this.getBoundingBoxToWorld()); 284 //} 285 }, 286 287 /** 288 * set the dirty node 289 */ 290 setNodeDirty:function () { 291 this._setNodeDirtyForCache(); 292 this._transformDirty = this._inverseDirty = true; 293 if (cc.NODE_TRANSFORM_USING_AFFINE_MATRIX) { 294 this._transformGLDirty = true; 295 } 296 }, 297 298 _setNodeDirtyForCache:function () { 299 this._cacheDirty = true; 300 if (this._parent) { 301 this._parent._setNodeDirtyForCache(); 302 } 303 }, 304 305 /** 306 * get the skew degrees in X 307 * @return {Number} 308 */ 309 getSkewX:function () { 310 return this._skewX; 311 }, 312 313 /** 314 * set the skew degrees in X 315 * @param {Number} newSkewX 316 */ 317 setSkewX:function (newSkewX) { 318 //save dirty region when before change 319 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 320 321 this._skewX = newSkewX; 322 323 //save dirty region when after changed 324 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 325 this.setNodeDirty(); 326 }, 327 328 /** get the skew degrees in Y 329 * @return {Number} 330 */ 331 getSkewY:function () { 332 return this._skewY; 333 }, 334 335 /** 336 * set the skew degrees in Y 337 * @param {Number} newSkewY 338 */ 339 setSkewY:function (newSkewY) { 340 //save dirty region when before change 341 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 342 343 this._skewY = newSkewY; 344 //save dirty region when after changed 345 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 346 this.setNodeDirty(); 347 }, 348 349 /** 350 * zOrder getter 351 * @return {Number} 352 */ 353 getZOrder:function () { 354 return this._zOrder; 355 }, 356 357 /** zOrder setter : private method 358 * used internally to alter the zOrder variable. DON'T call this method manually 359 * @param {Number} z 360 * @private 361 */ 362 _setZOrder:function (z) { 363 this._zOrder = z; 364 }, 365 366 setZOrder:function (z) { 367 this._setZOrder(z); 368 if (this._parent) { 369 this._parent.reorderChild(this, z); 370 } 371 }, 372 373 /** 374 * ertexZ getter 375 * @return {Number} 376 */ 377 getVertexZ:function () { 378 return this._vertexZ; 379 }, 380 381 /** 382 * vertexZ setter 383 * @param {Number} Var 384 */ 385 setVertexZ:function (Var) { 386 this._vertexZ = Var; 387 }, 388 389 /** 390 * rotation getter 391 * @return {Number} 392 */ 393 getRotation:function () { 394 return this._rotation; 395 }, 396 397 _rotationRadians:0, 398 /** 399 * rotation setter 400 * @param {Number} newRotation 401 */ 402 setRotation:function (newRotation) { 403 if (this._rotation == newRotation) 404 return; 405 this._rotation = newRotation; 406 this._rotationRadians = this._rotation * (Math.PI / 180); 407 408 this.setNodeDirty(); 409 }, 410 411 /** Get the scale factor of the node. 412 * @warning: Assert when _scaleX != _scaleY. 413 * @return {Number} 414 */ 415 getScale:function () { 416 cc.Assert(this._scaleX == this._scaleY, "cc.Node#scale. ScaleX != ScaleY. Don't know which one to return"); 417 return this._scaleX; 418 }, 419 420 /** 421 * The scale factor of the node. 1.0 is the default scale factor. 422 * @param {Number} scale or scaleX value 423 * @param {Number} scaleY 424 */ 425 setScale:function (scale, scaleY) { 426 //save dirty region when before change 427 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 428 429 this._scaleX = scale; 430 this._scaleY = scaleY || scale; 431 432 //save dirty region when after changed 433 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 434 this.setNodeDirty(); 435 }, 436 437 /** 438 * scaleX getter 439 * @return {Number} 440 */ 441 getScaleX:function () { 442 return this._scaleX; 443 }, 444 445 /** 446 * scaleX setter 447 * @param {Number} newScaleX 448 */ 449 setScaleX:function (newScaleX) { 450 //save dirty region when before change 451 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 452 453 this._scaleX = newScaleX; 454 455 //save dirty region when after changed 456 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 457 this.setNodeDirty(); 458 }, 459 460 /** 461 * scaleY getter 462 * @return {Number} 463 */ 464 getScaleY:function () { 465 return this._scaleY; 466 }, 467 468 /** 469 * scaleY setter 470 * @param {Number} newScaleY 471 */ 472 setScaleY:function (newScaleY) { 473 //save dirty region when before change 474 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 475 476 this._scaleY = newScaleY; 477 478 //save dirty region when after changed 479 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 480 this.setNodeDirty(); 481 }, 482 483 /** 484 * position setter 485 * @param {cc.Point|Number} newPosOrxValue 486 * @param {Number} yValue 487 */ 488 setPosition:function (newPosOrxValue, yValue) { 489 //save dirty region when before change 490 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 491 if (arguments.length == 2) { 492 this._position = new cc.Point(newPosOrxValue, yValue); 493 //this.setPosition = this._setPositionByValue; 494 } else if (arguments.length == 1) { 495 this._position = new cc.Point(newPosOrxValue.x, newPosOrxValue.y); 496 //this.setPosition = this._setPositionByValue; 497 } 498 //save dirty region when after changed 499 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 500 this.setNodeDirty(); 501 }, 502 503 _setPositionByValue:function (newPosOrxValue, yValue) { 504 if (arguments.length == 2) { 505 this._position.x = newPosOrxValue; 506 this._position.y = yValue; 507 //this._position = cc.p(newPosOrxValue,yValue); 508 } else if (arguments.length == 1) { 509 this._position.x = newPosOrxValue.x; 510 this._position.y = newPosOrxValue.y; 511 } 512 this.setNodeDirty(); 513 }, 514 515 /** <p>get/set Position for Lua (pass number faster than cc.Point object)</p> 516 517 <p>lua code:<br/> 518 local x, y = node:getPosition() -- return x, y values from C++ <br/> 519 local x = node:getPositionX()<br/> 520 local y = node:getPositionY()<br/> 521 node:setPosition(x, y) -- pass x, y values to C++ <br/> 522 node:setPositionX(x) <br/> 523 node:setPositionY(y)<br/> 524 node:setPositionInPixels(x, y) -- pass x, y values to C++ <br/></P> 525 * @return {cc.Point} 526 */ 527 getPosition:function () { 528 return cc.p(this._position.x, this._position.y); 529 }, 530 531 /** 532 * @return {Number} 533 */ 534 getPositionX:function () { 535 return this._position.x; 536 }, 537 538 /** 539 * @param {Number} x 540 */ 541 setPositionX:function (x) { 542 this._position.x = x; 543 //this._position = cc.p(x,this._position.y); 544 this.setNodeDirty(); 545 }, 546 547 /** 548 * @return {Number} 549 */ 550 getPositionY:function () { 551 return this._position.y; 552 }, 553 554 /** 555 * @param {Number} y 556 */ 557 setPositionY:function (y) { 558 this._position.y = y; 559 //this._position = cc.p(this._position.x, y); 560 this.setNodeDirty(); 561 }, 562 563 /** 564 * Get children count 565 * @return {Number} 566 */ 567 568 getChildrenCount:function () { 569 return this._children ? this._children.length : 0; 570 }, 571 572 /** 573 * children getter 574 * @return {object} 575 */ 576 getChildren:function () { 577 if (!this._children) 578 this._children = []; 579 return this._children; 580 }, 581 582 /** 583 * camera getter: lazy alloc 584 * @return {cc.Camera} 585 */ 586 getCamera:function () { 587 if (!this._camera) { 588 this._camera = new cc.Camera(); 589 } 590 return this._camera; 591 }, 592 593 /** 594 * grid getter 595 * @return {cc.GridBase} 596 */ 597 getGrid:function () { 598 return this._grid; 599 }, 600 601 /** 602 * grid setter 603 * @param {cc.GridBase} grid 604 */ 605 setGrid:function (grid) { 606 this._grid = grid; 607 }, 608 609 /** 610 * isVisible getter 611 * @return {Boolean} 612 */ 613 isVisible:function () { 614 return this._visible; 615 }, 616 617 /** 618 * isVisible setter 619 * @param {Boolean} Var 620 */ 621 setVisible:function (Var) { 622 this._visible = Var; 623 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 624 this.setNodeDirty(); 625 }, 626 627 /** <p>anchorPoint is the point around which all transformations and positioning manipulations take place.<br/> 628 It's like a pin in the node where it is "attached" to its parent. <br/> 629 The anchorPoint is normalized, like a percentage. (0,0) means the bottom-left corner and (1,1) means the top-right corner. <br/> 630 But you can use values higher than (1,1) and lower than (0,0) too. <br/> 631 The default anchorPoint is (0.5,0.5), so it starts in the center of the node. <br/></p> 632 */ 633 getAnchorPoint:function () { 634 return cc.p(this._anchorPoint.x, this._anchorPoint.y); 635 }, 636 637 /** 638 * @param {cc.Point} point 639 */ 640 setAnchorPoint:function (point) { 641 if (!cc.Point.CCPointEqualToPoint(point, this._anchorPoint)) { 642 //save dirty region when before change 643 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 644 645 this._anchorPoint = new cc.Point(point.x, point.y); 646 this._anchorPointInPoints = new cc.Point(this._contentSize.width * this._anchorPoint.x, this._contentSize.height * this._anchorPoint.y); 647 648 //this.setAnchorPoint = this._setAnchorPointByValue; 649 650 //save dirty region when after changed 651 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 652 this.setNodeDirty(); 653 } 654 }, 655 656 _setAnchorPointByValue:function (point) { 657 if (!cc.Point.CCPointEqualToPoint(point, this._anchorPoint)) { 658 this._anchorPoint.x = point.x; 659 this._anchorPoint.y = point.y; 660 this._anchorPointInPoints.x = this._contentSize.width * this._anchorPoint.x; 661 this._anchorPointInPoints.y = this._contentSize.height * this._anchorPoint.y; 662 this.setNodeDirty(); 663 } 664 }, 665 666 /** AnchorPointInPoints getter 667 * @return {cc.Point} 668 */ 669 getAnchorPointInPoints:function () { 670 return cc.p(this._anchorPointInPoints.x, this._anchorPointInPoints.y); 671 }, 672 673 /** <p>The untransformed size of the node. <br/> 674 The contentSize remains the same no matter the node is scaled or rotated.<br/> 675 All nodes has a size. Layer and Scene has the same size of the screen. <br/></p> 676 * @return {cc.Size} 677 */ 678 getContentSize:function () { 679 return cc.size(this._contentSize.width, this._contentSize.height); 680 }, 681 682 /** 683 * @param {cc.Size} size 684 */ 685 setContentSize:function (size) { 686 if (!cc.Size.CCSizeEqualToSize(size, this._contentSize)) { 687 //save dirty region when before change 688 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 689 this._contentSize = new cc.Size(size.width, size.height); 690 this._anchorPointInPoints = new cc.Point(this._contentSize.width * this._anchorPoint.x, this._contentSize.height * this._anchorPoint.y); 691 //save dirty region when before change 692 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 693 //this.setContentSize = this._setContentSizeByValue; 694 this.setNodeDirty(); 695 } 696 }, 697 698 _setContentSizeByValue:function (size) { 699 if (!cc.Size.CCSizeEqualToSize(size, this._contentSize)) { 700 this._contentSize.width = size.width; 701 this._contentSize.height = size.height; 702 this._anchorPointInPoints.x = this._contentSize.width * this._anchorPoint.x; 703 this._anchorPointInPoints.y = this._contentSize.height * this._anchorPoint.y; 704 this.setNodeDirty(); 705 } 706 }, 707 708 /** 709 * isRunning getter 710 * @return {Boolean} 711 */ 712 isRunning:function () { 713 return this._running; 714 }, 715 716 /** parent getter 717 * @return {cc.Node} 718 */ 719 getParent:function () { 720 return this._parent; 721 }, 722 723 /** parent setter 724 * @param {cc.Node} Var 725 */ 726 setParent:function (Var) { 727 this._parent = Var; 728 }, 729 730 /** ignoreAnchorPointForPosition getter 731 * @return {Boolean} 732 */ 733 isIgnoreAnchorPointForPosition:function () { 734 return this._ignoreAnchorPointForPosition; 735 }, 736 737 /** ignoreAnchorPointForPosition setter 738 * @param {Boolean} newValue 739 */ 740 ignoreAnchorPointForPosition:function (newValue) { 741 if (newValue != this._ignoreAnchorPointForPosition) { 742 //save dirty region when before change 743 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 744 745 this._ignoreAnchorPointForPosition = newValue; 746 747 //save dirty region when before change 748 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 749 this.setNodeDirty(); 750 } 751 }, 752 753 /** 754 * tag getter 755 * @return {Number} 756 */ 757 getTag:function () { 758 return this._tag; 759 }, 760 761 /** tag setter 762 * @param {Number} Var 763 */ 764 setTag:function (Var) { 765 this._tag = Var; 766 }, 767 768 /** 769 * @return {object} 770 */ 771 getUserData:function () { 772 return this._userData; 773 }, 774 775 /** 776 * @param {object} Var 777 */ 778 setUserData:function (Var) { 779 this._userData = Var; 780 }, 781 782 /** 783 * Similar to userData, but instead of holding a void* it holds an id 784 * @return {object} 785 */ 786 getUserObject:function () { 787 return this._userObject; 788 }, 789 790 /** 791 * Similar to userData, but instead of holding a void* it holds an id 792 * @param {object} newValue 793 */ 794 setUserObject:function (newValue) { 795 if (this._userObject != newValue) { 796 this._userObject = newValue; 797 } 798 }, 799 800 /** 801 * Shader Program getter 802 * @return {object} 803 */ 804 getShaderProgram:function () { 805 return this._shaderProgram; 806 }, 807 808 /** 809 * Shader Program setter 810 * @param {object} newValue 811 */ 812 setShaderProgram:function (newValue) { 813 if (this._shaderProgram != newValue) { 814 this._shaderProgram = newValue; 815 } 816 }, 817 818 /** 819 * used internally for zOrder sorting, don't change this manually 820 * @return {Number} 821 */ 822 getOrderOfArrival:function () { 823 return this._orderOfArrival; 824 }, 825 826 /** 827 * used internally for zOrder sorting, don't change this manually 828 * @param {Number} Var 829 */ 830 setOrderOfArrival:function (Var) { 831 this._orderOfArrival = Var; 832 }, 833 834 /** 835 * GL server side state getter 836 * @return {Number} 837 */ 838 getGLServerState:function () { 839 return this._glServerState; 840 }, 841 842 /** 843 * GL server side state setter 844 * @param {Number} Var 845 */ 846 setGLServerState:function (Var) { 847 this._glServerState = Var; 848 }, 849 850 /** 851 * <p>cc.ActionManager used by all the actions. <br/> 852 * (IMPORTANT: If you set a new cc.ActionManager, then previously created actions are going to be removed.)</p> 853 * @return {cc.ActionManager} 854 */ 855 getActionManager:function () { 856 if (!this._actionManager) { 857 this._actionManager = cc.Director.getInstance().getActionManager(); 858 this.getActionManager = function () { 859 return this._actionManager; 860 }; 861 } 862 863 return this._actionManager; 864 }, 865 866 /** 867 * <p>cc.ActionManager used by all the actions. <br/> 868 * (IMPORTANT: If you set a new cc.ActionManager, then previously created actions are going to be removed.)</p> 869 * @param {cc.ActionManager} actionManager 870 */ 871 setActionManager:function (actionManager) { 872 if (this._actionManager != actionManager) { 873 this.stopAllActions(); 874 this._shaderProgram = actionManager; 875 } 876 }, 877 878 /** 879 * <p> 880 * cc.Scheduler used to schedule all "updates" and timers.<br/> 881 * IMPORTANT: If you set a new cc.Scheduler, then previously created timers/update are going to be removed. 882 * </p> 883 * @return {cc.Scheduler} 884 */ 885 getScheduler:function () { 886 if (!this._scheduler) { 887 this._scheduler = cc.Director.getInstance().getScheduler(); 888 this.getScheduler = function () { 889 return this._scheduler; 890 }; 891 } 892 return this._scheduler; 893 }, 894 895 /** 896 * <p> 897 * cc.Scheduler used to schedule all "updates" and timers.<br/> 898 * IMPORTANT: If you set a new cc.Scheduler, then previously created timers/update are going to be removed. 899 * </p> 900 */ 901 setScheduler:function (scheduler) { 902 if (this._scheduler != scheduler) { 903 this.unscheduleAllCallbacks(); 904 this._scheduler = scheduler; 905 } 906 }, 907 908 /** returns a "local" axis aligned bounding box of the node. <br/> 909 * The returned box is relative only to its parent. 910 * @return {cc.Rect} 911 */ 912 getBoundingBox:function () { 913 var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height); 914 return cc.RectApplyAffineTransform(rect, this.nodeToParentTransform()); 915 }, 916 917 /** returns a "world" axis aligned bounding box of the node. <br/> 918 * @return {cc.Rect} 919 */ 920 getBoundingBoxToWorld:function () { 921 var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height); 922 rect = cc.RectApplyAffineTransform(rect, this.nodeToWorldTransform()); 923 rect = cc.rect(0 | rect.origin.x - 4, 0 | rect.origin.y - 4, 0 | rect.size.width + 8, 0 | rect.size.height + 8); 924 //query child's BoundingBox 925 if (!this._children) 926 return rect; 927 928 for (var i = 0; i < this._children.length; i++) { 929 var child = this._children[i]; 930 if (child && child._visible) { 931 var childRect = child.getBoundingBoxToWorld(); 932 if (childRect) { 933 rect = cc.Rect.CCRectUnion(rect, childRect); 934 } 935 } 936 } 937 return rect; 938 }, 939 /** 940 * Stops all running actions and schedulers 941 */ 942 cleanup:function () { 943 // actions 944 this.stopAllActions(); 945 this.unscheduleAllCallbacks(); 946 947 // timers 948 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.cleanup); 949 }, 950 951 /** Node description 952 * @return {String} 953 */ 954 description:function () { 955 return "<cc.Node | Tag =" + this._tag + ">"; 956 }, 957 958 _childrenAlloc:function () { 959 this._children = []; 960 }, 961 962 // composition: GET 963 /** 964 * Gets a child from the container given its tag 965 * @param {Number} aTag 966 * @return {cc.Node} 967 */ 968 getChildByTag:function (aTag) { 969 cc.Assert(aTag != cc.NODE_TAG_INVALID, "Invalid tag"); 970 if (this._children != null) { 971 for (var i = 0; i < this._children.length; i++) { 972 var node = this._children[i]; 973 if (node && node._tag == aTag) { 974 return node; 975 } 976 } 977 } 978 //throw "not found"; 979 return null; 980 }, 981 // composition: ADD 982 983 /** <p>"add" logic MUST only be on this method <br/> </p> 984 * 985 * <p>If a class want's to extend the 'addChild' behaviour it only needs <br/> 986 * to override this method </p> 987 * 988 * @param {cc.Node} child 989 * @param {Number} zOrder 990 * @param {Number} tag 991 */ 992 addChild:function (child, zOrder, tag) { 993 if (child === this) { 994 console.warn('cc.Node.addChild: An Node can\'t be added as a child of itself.'); 995 return; 996 } 997 998 cc.Assert(child != null, "Argument must be non-nil"); 999 cc.Assert(child._parent == null, "child already added. It can't be added again"); 1000 var tempzOrder = (zOrder != null) ? zOrder : child.getZOrder(); 1001 var tmptag = (tag != null) ? tag : child.getTag(); 1002 child.setTag(tmptag); 1003 1004 if (!this._children) { 1005 this._childrenAlloc(); 1006 } 1007 1008 this._insertChild(child, tempzOrder); 1009 1010 child.setParent(this); 1011 if (this._running) { 1012 child.onEnter(); 1013 child.onEnterTransitionDidFinish(); 1014 } 1015 1016 }, 1017 1018 // composition: REMOVE 1019 /** Remove itself from its parent node. If cleanup is true, then also remove all actions and callbacks. <br/> 1020 * If the cleanup parameter is not passed, it will force a cleanup. <br/> 1021 * If the node orphan, then nothing happens. 1022 * @param {Boolean} cleanup 1023 */ 1024 removeFromParent:function (cleanup) { 1025 if (this._parent) { 1026 cleanup = cleanup || true; 1027 this._parent.removeChild(this, cleanup); 1028 } 1029 }, 1030 /** XXX deprecated */ 1031 removeFromParentAndCleanup:function (cleanup) { 1032 cc.log("removeFromParentAndCleanup is deprecated. Use removeFromParent instead"); 1033 this.removeFromParent(cleanup); 1034 }, 1035 1036 /** <p>Removes a child from the container. It will also cleanup all running actions depending on the cleanup parameter. </p> 1037 * If the cleanup parameter is not passed, it will force a cleanup. <br/> 1038 *<p> "remove" logic MUST only be on this method <br/> 1039 * If a class wants to extend the 'removeChild' behavior it only needs <br/> 1040 * to override this method </p> 1041 * 1042 * @param {cc.Node} child 1043 * @param {Boolean} cleanup 1044 */ 1045 removeChild:function (child, cleanup) { 1046 // explicit nil handling 1047 if (this._children == null) { 1048 return; 1049 } 1050 1051 cleanup = cleanup || true; 1052 if (this._children.indexOf(child) > -1) { 1053 this._detachChild(child, cleanup); 1054 } 1055 1056 this.setNodeDirty(); 1057 }, 1058 1059 /** 1060 * Removes a child from the container by tag value. It will also cleanup all running actions depending on the cleanup parameter. 1061 * If the cleanup parameter is not passed, it will force a cleanup. <br/> 1062 * @param {Number} tag 1063 * @param {Boolean} cleanup 1064 */ 1065 removeChildByTag:function (tag, cleanup) { 1066 cc.Assert(tag != cc.NODE_TAG_INVALID, "Invalid tag"); 1067 1068 var child = this.getChildByTag(tag); 1069 if (child == null) { 1070 cc.log("cocos2d: removeChildByTag: child not found!"); 1071 } else { 1072 this.removeChild(child, cleanup); 1073 } 1074 }, 1075 1076 /* XXX deprecated */ 1077 removeAllChildrenWithCleanup:function (cleanup) { 1078 cc.log("removeAllChildrenWithCleanup is deprecated. Use removeAllChildren instead"); 1079 this.removeAllChildren(cleanup); 1080 }, 1081 1082 /** 1083 * Removes all children from the container and do a cleanup all running actions depending on the cleanup parameter. 1084 * If the cleanup parameter is not passed, it will force a cleanup. <br/> 1085 * @param {Boolean} cleanup 1086 */ 1087 removeAllChildren:function (cleanup) { 1088 // not using detachChild improves speed here 1089 if (this._children != null) { 1090 cleanup = cleanup || true; 1091 for (var i = 0; i < this._children.length; i++) { 1092 var node = this._children[i]; 1093 if (node) { 1094 // IMPORTANT: 1095 // -1st do onExit 1096 // -2nd cleanup 1097 if (this._running) { 1098 node.onExitTransitionDidStart(); 1099 node.onExit(); 1100 } 1101 if (cleanup) 1102 node.cleanup(); 1103 // set parent nil at the end 1104 node.setParent(null); 1105 } 1106 } 1107 this._children.length = 0; 1108 } 1109 }, 1110 1111 /** 1112 * @param {cc.Node} child 1113 * @param {Boolean} doCleanup 1114 * @private 1115 */ 1116 _detachChild:function (child, doCleanup) { 1117 // IMPORTANT: 1118 // -1st do onExit 1119 // -2nd cleanup 1120 if (this._running) { 1121 child.onExitTransitionDidStart(); 1122 child.onExit(); 1123 } 1124 1125 // If you don't do cleanup, the child's actions will not get removed and the 1126 // its scheduledSelectors_ dict will not get released! 1127 if (doCleanup) { 1128 child.cleanup(); 1129 } 1130 1131 // set parent nil at the end 1132 child.setParent(null); 1133 1134 cc.ArrayRemoveObject(this._children, child); 1135 }, 1136 1137 /** helper used by reorderChild & add 1138 * @param {cc.Node} child 1139 * @param {Number} z 1140 * @private 1141 */ 1142 _insertChild:function (child, z) { 1143 this._reorderChildDirty = true; 1144 var a = this._children[this._children.length - 1]; 1145 if (!a || a.getZOrder() <= z) { 1146 this._children.push(child); 1147 } else { 1148 for (var i = 0; i < this._children.length; i++) { 1149 var node = this._children[i]; 1150 if (node && (node.getZOrder() > z )) { 1151 this._children = cc.ArrayAppendObjectToIndex(this._children, child, i); 1152 break; 1153 } 1154 } 1155 } 1156 child._setZOrder(z); 1157 }, 1158 1159 /** Reorders a child according to a new z value. <br/> 1160 * The child MUST be already added. 1161 * @param {cc.Node} child 1162 * @param {Number} zOrder 1163 */ 1164 reorderChild:function (child, zOrder) { 1165 cc.Assert(child != null, "Child must be non-nil"); 1166 this._reorderChildDirty = true; 1167 1168 //save dirty region when before change 1169 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 1170 1171 child.setOrderOfArrival(cc.s_globalOrderOfArrival++); 1172 child._setZOrder(zOrder); 1173 1174 //save dirty region when after changed 1175 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 1176 this.setNodeDirty(); 1177 }, 1178 1179 /** 1180 * <p>performance improvement, Sort the children array once before drawing, instead of every time when a child is added or reordered <br/> 1181 * don't call this manually unless a child added needs to be removed in the same frame </p> 1182 */ 1183 sortAllChildren:function () { 1184 if (this._reorderChildDirty) { 1185 var i, j, length = this._children.length; 1186 1187 // insertion sort 1188 for (i = 0; i < length; i++) { 1189 var tempItem = this._children[i]; 1190 j = i - 1; 1191 1192 //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller 1193 while (j >= 0 && ( tempItem._zOrder < this._children[j]._zOrder || 1194 ( tempItem._zOrder == this._children[j]._zOrder && tempItem._orderOfArrival < this._children[j]._orderOfArrival ))) { 1195 this._children[j + 1] = this._children[j]; 1196 j = j - 1; 1197 } 1198 this._children[j + 1] = tempItem; 1199 } 1200 1201 //don't need to check children recursively, that's done in visit of each child 1202 this._reorderChildDirty = false; 1203 } 1204 }, 1205 1206 // draw 1207 /** <p>Override this method to draw your own node. <br/> 1208 * The following GL states will be enabled by default: <br/> 1209 - glEnableClientState(GL_VERTEX_ARRAY); <br/> 1210 - glEnableClientState(GL_COLOR_ARRAY); <br/> 1211 - glEnableClientState(GL_TEXTURE_COORD_ARRAY); <br/> 1212 - glEnable(GL_TEXTURE_2D); </p> 1213 1214 <p>AND YOU SHOULD NOT DISABLE THEM AFTER DRAWING YOUR NODE</p> 1215 1216 <p>But if you enable any other GL state, you should disable it after drawing your node. </p> 1217 * @param {CanvasContext} ctx 1218 */ 1219 draw:function (ctx) { 1220 //cc.Assert(0); 1221 // override me 1222 // Only use- this function to draw your staff. 1223 // DON'T draw your stuff outside this method 1224 }, 1225 1226 /** 1227 * recursive method that visit its children and draw them 1228 * @param {CanvasContext} ctx 1229 */ 1230 visit:function (ctx) { 1231 //visit for canvas 1232 1233 // quick return if not visible 1234 if (!this._visible) 1235 return; 1236 1237 var context = ctx || cc.renderContext, i; 1238 context.save(); 1239 this.transform(context); 1240 if (this._children && this._children.length > 0) { 1241 this.sortAllChildren(); 1242 // draw children zOrder < 0 1243 for (i = 0; i < this._children.length; i++) { 1244 if (this._children[i] && this._children[i]._zOrder < 0) 1245 this._children[i].visit(context); 1246 else 1247 break; 1248 } 1249 this.draw(context); 1250 if (this._children) { 1251 for (; i < this._children.length; i++) { 1252 if (this._children[i] && this._children[i]._zOrder >= 0) 1253 this._children[i].visit(context); 1254 } 1255 } 1256 } else 1257 this.draw(context); 1258 1259 this._orderOfArrival = 0; 1260 context.restore(); 1261 }, 1262 1263 _visitForWebGL:function (ctx) { 1264 if (!this._visible) 1265 return; 1266 1267 var context = ctx, i; 1268 1269 context.save(); 1270 1271 if (this._grid && this._grid.isActive()) { 1272 this._grid.beforeDraw(); 1273 } 1274 1275 this.transform(context); 1276 if (this._children && this._children.length > 0) { 1277 this.sortAllChildren(); 1278 // draw children zOrder < 0 1279 for (i = 0; i < this._children.length; i++) { 1280 if (this._children[i] && this._children[i]._zOrder < 0) { 1281 this._children[i].visit(context); 1282 } else { 1283 break; 1284 } 1285 } 1286 1287 //if (this._isInDirtyRegion()) { 1288 // self draw 1289 this.draw(context); 1290 //} 1291 1292 // draw children zOrder >= 0 1293 if (this._children) { 1294 for (; i < this._children.length; i++) { 1295 if (this._children[i] && this._children[i]._zOrder >= 0) { 1296 this._children[i].visit(context); 1297 } 1298 } 1299 } 1300 } else { 1301 //if (this._isInDirtyRegion()) { 1302 // self draw 1303 this.draw(context); 1304 //} 1305 } 1306 1307 this._orderOfArrival = 0; 1308 if (this._grid && this._grid.isActive()) { 1309 this._grid.afterDraw(this); 1310 } 1311 context.restore(); 1312 }, 1313 1314 /** performs OpenGL view-matrix transformation of it's ancestors.<br/> 1315 * Generally the ancestors are already transformed, but in certain cases (eg: attaching a FBO) <br/> 1316 * it's necessary to transform the ancestors again. 1317 */ 1318 transformAncestors:function () { 1319 if (this._parent != null) { 1320 this._parent.transformAncestors(); 1321 this._parent.transform(); 1322 } 1323 }, 1324 1325 /** transformations <br/> 1326 * performs OpenGL view-matrix transformation based on position, scale, rotation and other attributes. 1327 * @param {CanvasContext} ctx 1328 */ 1329 transform:function (ctx) { 1330 // transform for canvas 1331 var context = ctx || cc.renderContext; 1332 1333 // transformations 1334 if (!this._ignoreAnchorPointForPosition) { 1335 if (this._parent) 1336 context.translate(0 | (this._position.x - this._parent._anchorPointInPoints.x), -(0 | (this._position.y - this._parent._anchorPointInPoints.y))); 1337 else 1338 context.translate(0 | this._position.x, -(0 | this._position.y)); 1339 } else { 1340 if (this._parent) { 1341 context.translate(0 | ( this._position.x - this._parent._anchorPointInPoints.x + this._anchorPointInPoints.x), 1342 -(0 | (this._position.y - this._parent._anchorPointInPoints.y + this._anchorPointInPoints.y))); 1343 } else { 1344 context.translate(0 | ( this._position.x + this._anchorPointInPoints.x), -(0 | (this._position.y + this._anchorPointInPoints.y))); 1345 } 1346 } 1347 1348 if (this._rotation != 0) 1349 context.rotate(this._rotationRadians); 1350 1351 if ((this._scaleX != 1) || (this._scaleY != 1)) 1352 context.scale(this._scaleX, this._scaleY); 1353 1354 if ((this._skewX != 0) || (this._skewY != 0)) { 1355 context.transform(1, 1356 -Math.tan(cc.DEGREES_TO_RADIANS(this._skewY)), 1357 -Math.tan(cc.DEGREES_TO_RADIANS(this._skewX)), 1358 1, 0, 0); 1359 } 1360 }, 1361 1362 _transformForWebGL:function (ctx) { 1363 var context = ctx; 1364 1365 //Todo WebGL implement need fixed 1366 var transfrom4x4; 1367 1368 // Convert 3x3 into 4x4 matrix 1369 var tmpAffine = this.nodeToParentTransform(); 1370 //CGAffineToGL(&tmpAffine, transfrom4x4.mat); 1371 1372 // Update Z vertex manually 1373 //transfrom4x4.mat[14] = m_fVertexZ; 1374 1375 //kmGLMultMatrix( &transfrom4x4 ); 1376 1377 1378 // XXX: Expensive calls. Camera should be integrated into the cached affine matrix 1379 /*if ( m_pCamera != NULL && !(m_pGrid != NULL && m_pGrid->isActive()) ) { 1380 bool translate = (m_tAnchorPointInPoints.x != 0.0f || m_tAnchorPointInPoints.y != 0.0f); 1381 1382 if( translate ) 1383 kmGLTranslatef(RENDER_IN_SUBPIXEL(m_tAnchorPointInPoints.x), RENDER_IN_SUBPIXEL(m_tAnchorPointInPoints.y), 0 ); 1384 1385 m_pCamera->locate(); 1386 1387 if( translate ) 1388 kmGLTranslatef(RENDER_IN_SUBPIXEL(-m_tAnchorPointInPoints.x), RENDER_IN_SUBPIXEL(-m_tAnchorPointInPoints.y), 0 ); 1389 }*/ 1390 }, 1391 1392 //scene managment 1393 /** 1394 * callback that is called every time the cc.Node enters the 'stage'.<br/> 1395 * If the cc.Node enters the 'stage' with a transition, this callback is called when the transition starts. 1396 * During onEnter you can't a "sister/brother" node. 1397 */ 1398 onEnter:function () { 1399 this._running = true;//should be running before resumeSchedule 1400 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onEnter); 1401 this.resumeSchedulerAndActions(); 1402 }, 1403 1404 /** 1405 * <p>callback that is called when the cc.Node enters in the 'stage'. <br/> 1406 * If the cc.Node enters the 'stage' with a transition, this callback is called when the transition finishes.</p> 1407 */ 1408 onEnterTransitionDidFinish:function () { 1409 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onEnterTransitionDidFinish); 1410 }, 1411 1412 /** 1413 * <p>callback that is called every time the cc.Node leaves the 'stage'. <br/> 1414 * If the cc.Node leaves the 'stage' with a transition, this callback is called when the transition starts. </p> 1415 */ 1416 onExitTransitionDidStart:function () { 1417 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onExitTransitionDidStart); 1418 }, 1419 1420 /** 1421 * callback that is called every time the cc.Node leaves the 'stage'.<br/> 1422 * If the cc.Node leaves the 'stage' with a transition, this callback is called when the transition finishes. <br/> 1423 * During onExit you can't access a sibling node. 1424 */ 1425 onExit:function () { 1426 this._running = false; 1427 this.pauseSchedulerAndActions(); 1428 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onExit); 1429 }, 1430 1431 // actions 1432 /** 1433 * Executes an action, and returns the action that is executed.<br/> 1434 * The node becomes the action's target. 1435 * @warning Starting from v0.8 actions don't retain their target anymore. 1436 * @param {cc.Action} action 1437 * @return {cc.Action} 1438 */ 1439 runAction:function (action) { 1440 cc.Assert(action != null, "Argument must be non-nil"); 1441 this.getActionManager().addAction(action, this, !this._running); 1442 return action; 1443 }, 1444 1445 /** 1446 * Removes all actions from the running action list 1447 */ 1448 stopAllActions:function () { 1449 this.getActionManager().removeAllActionsFromTarget(this); 1450 }, 1451 1452 /** 1453 * Removes an action from the running action list 1454 * @param {cc.Action} action 1455 */ 1456 stopAction:function (action) { 1457 this.getActionManager().removeAction(action); 1458 }, 1459 1460 /** 1461 * Removes an action from the running action list given its tag 1462 * @param {Number} tag 1463 */ 1464 stopActionByTag:function (tag) { 1465 cc.Assert(tag != cc.ACTION_TAG_INVALID, "Invalid tag"); 1466 this.getActionManager().removeActionByTag(tag, this); 1467 }, 1468 1469 /** 1470 * Gets an action from the running action list given its tag 1471 * @param {Number} tag 1472 * @return {cc.Action} 1473 */ 1474 getActionByTag:function (tag) { 1475 cc.Assert(tag != cc.ACTION_TAG_INVALID, "Invalid tag"); 1476 return this.getActionManager().getActionByTag(tag, this); 1477 }, 1478 1479 /** Returns the numbers of actions that are running plus the ones that are schedule to run (actions in actionsToAdd and actions arrays).<br/> 1480 * Composable actions are counted as 1 action. Example:<br/> 1481 * If you are running 1 Sequence of 7 actions, it will return 1. <br/> 1482 * If you are running 7 Sequences of 2 actions, it will return 7. 1483 * @return {Number} 1484 */ 1485 numberOfRunningActions:function () { 1486 return this.getActionManager().numberOfRunningActionsInTarget(this); 1487 }, 1488 1489 // cc.Node - Callbacks 1490 // timers 1491 /** 1492 * schedules the "update" method. It will use the order number 0. This method will be called every frame.<br/> 1493 * Scheduled methods with a lower order value will be called before the ones that have a higher order value.<br/> 1494 * Only one "update" method could be scheduled per node. 1495 */ 1496 scheduleUpdate:function () { 1497 this.scheduleUpdateWithPriority(0); 1498 }, 1499 1500 /** 1501 * schedules the "update" callback function with a custom priority. This callback function will be called every frame.<br/> 1502 * Scheduled callback functions with a lower priority will be called before the ones that have a higher value.<br/> 1503 * Only one "update" callback function could be scheduled per node (You can't have 2 'update' callback functions).<br/> 1504 * @param {Number} priority 1505 */ 1506 scheduleUpdateWithPriority:function (priority) { 1507 this.getScheduler().scheduleUpdateForTarget(this, priority, !this._running); 1508 }, 1509 1510 /** 1511 * unschedules the "update" method. 1512 */ 1513 unscheduleUpdate:function () { 1514 this.getScheduler().unscheduleUpdateForTarget(this); 1515 }, 1516 1517 /** 1518 * schedules a callback function with interval, repeat and delay. 1519 * @param {function} callback_fn 1520 * @param {Number} interval 1521 */ 1522 schedule:function (callback_fn, interval, repeat, delay) { 1523 interval = interval || 0; 1524 1525 cc.Assert(callback_fn, "Argument must be non-nil"); 1526 cc.Assert(interval >= 0, "Argument must be positive"); 1527 1528 repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat; 1529 delay = delay || 0; 1530 1531 this.getScheduler().scheduleCallbackForTarget(this, callback_fn, interval, repeat, delay, !this._running); 1532 }, 1533 1534 /** 1535 * Schedules a callback function that runs only once, with a delay of 0 or larger 1536 * @param {cc.Class} callback_fn 1537 * @param {Number} delay 1538 */ 1539 scheduleOnce:function (callback_fn, delay) { 1540 this.schedule(callback_fn, 0.0, 0, delay); 1541 }, 1542 1543 /** 1544 * unschedules a custom callback function. 1545 * @param {function} callback_fn 1546 */ 1547 unschedule:function (callback_fn) { 1548 // explicit nil handling 1549 if (!callback_fn) 1550 return; 1551 1552 this.getScheduler().unscheduleCallbackForTarget(this, callback_fn); 1553 }, 1554 1555 /** 1556 * unschedule all scheduled callback functions: custom callback functions, and the 'update' callback function.<br/> 1557 * Actions are not affected by this method. 1558 */ 1559 unscheduleAllCallbacks:function () { 1560 this.getScheduler().unscheduleAllCallbacksForTarget(this); 1561 }, 1562 1563 /** 1564 * resumes all scheduled callback functions and actions.<br/> 1565 * Called internally by onEnter 1566 */ 1567 resumeSchedulerAndActions:function () { 1568 this.getScheduler().resumeTarget(this); 1569 this.getActionManager().resumeTarget(this); 1570 }, 1571 1572 /** 1573 * pauses all scheduled selectors and actions.<br/> 1574 * Called internally by onExit 1575 */ 1576 pauseSchedulerAndActions:function () { 1577 this.getScheduler().pauseTarget(this); 1578 this.getActionManager().pauseTarget(this); 1579 }, 1580 1581 /** Returns the matrix that transform the node's (local) space coordinates into the parent's space coordinates.<br/> 1582 * The matrix is in Pixels. 1583 * @return {cc.AffineTransform} 1584 */ 1585 nodeToParentTransform:function () { 1586 if (this._transformDirty) { 1587 // Translate values 1588 var x = this._position.x; 1589 var y = this._position.y; 1590 1591 if (this._ignoreAnchorPointForPosition) { 1592 x += this._anchorPointInPoints.x; 1593 y += this._anchorPointInPoints.y; 1594 } 1595 1596 // Rotation values 1597 var c = 1, s = 0; 1598 if (this._rotation) { 1599 //var radians = -cc.DEGREES_TO_RADIANS(this._rotation); 1600 c = Math.cos(-this._rotationRadians); 1601 s = Math.sin(-this._rotationRadians); 1602 } 1603 1604 var needsSkewMatrix = ( this._skewX || this._skewY ); 1605 1606 // optimization: 1607 // inline anchor point calculation if skew is not needed 1608 if (!needsSkewMatrix && !cc.Point.CCPointEqualToPoint(this._anchorPointInPoints, cc.p(0, 0))) { 1609 x += c * -this._anchorPointInPoints.x * this._scaleX + -s * -this._anchorPointInPoints.y * this._scaleY; 1610 y += s * -this._anchorPointInPoints.x * this._scaleX + c * -this._anchorPointInPoints.y * this._scaleY; 1611 } 1612 1613 // Build Transform Matrix 1614 this._transform = cc.AffineTransformMake(c * this._scaleX, s * this._scaleX, 1615 -s * this._scaleY, c * this._scaleY, x, y); 1616 1617 // XXX: Try to inline skew 1618 // If skew is needed, apply skew and then anchor point 1619 if (needsSkewMatrix) { 1620 var skewMatrix = cc.AffineTransformMake(1.0, Math.tan(cc.DEGREES_TO_RADIANS(this._skewY)), 1621 Math.tan(cc.DEGREES_TO_RADIANS(this._skewX)), 1.0, 0.0, 0.0); 1622 this._transform = cc.AffineTransformConcat(skewMatrix, this._transform); 1623 1624 // adjust anchor point 1625 if (!cc.Point.CCPointEqualToPoint(this._anchorPointInPoints, cc.p(0, 0))) { 1626 this._transform = cc.AffineTransformTranslate(this._transform, -this._anchorPointInPoints.x, -this._anchorPointInPoints.y); 1627 } 1628 } 1629 1630 this._transformDirty = false; 1631 } 1632 1633 return this._transform; 1634 }, 1635 1636 /** 1637 * Returns the matrix that transform parent's space coordinates to the node's (local) space coordinates.<br/> 1638 * The matrix is in Pixels. 1639 * @return {Number} 1640 */ 1641 parentToNodeTransform:function () { 1642 if (this._inverseDirty) { 1643 this._inverse = cc.AffineTransformInvert(this.nodeToParentTransform()); 1644 this._inverseDirty = false; 1645 } 1646 1647 return this._inverse; 1648 }, 1649 1650 /** 1651 * Retrusn the world affine transform matrix. The matrix is in Pixels. 1652 * @return {cc.AffineTransform} 1653 */ 1654 nodeToWorldTransform:function () { 1655 var t = this.nodeToParentTransform(); 1656 for (var p = this._parent; p != null; p = p.getParent()) { 1657 t = cc.AffineTransformConcat(t, p.nodeToParentTransform()); 1658 } 1659 return t; 1660 }, 1661 1662 /** 1663 * Returns the inverse world affine transform matrix. The matrix is in Pixels. 1664 * @return {cc.AffineTransform} 1665 */ 1666 worldToNodeTransform:function () { 1667 return cc.AffineTransformInvert(this.nodeToWorldTransform()); 1668 }, 1669 1670 /** 1671 * Converts a Point to node (local) space coordinates. The result is in Points. 1672 * @param {cc.Point} worldPoint 1673 * @return {cc.Point} 1674 */ 1675 convertToNodeSpace:function (worldPoint) { 1676 return cc.PointApplyAffineTransform(worldPoint, this.worldToNodeTransform()); 1677 }, 1678 1679 /** 1680 * Converts a Point to world space coordinates. The result is in Points. 1681 * @param {cc.Point} nodePoint 1682 * @return {cc.Point} 1683 */ 1684 convertToWorldSpace:function (nodePoint) { 1685 return cc.PointApplyAffineTransform(nodePoint, this.nodeToWorldTransform()); 1686 }, 1687 1688 /** 1689 * Converts a Point to node (local) space coordinates. The result is in Points.<br/> 1690 * treating the returned/received node point as anchor relative. 1691 * @param {cc.Point} worldPoint 1692 * @return {cc.Point} 1693 */ 1694 convertToNodeSpaceAR:function (worldPoint) { 1695 return cc.pSub(this.convertToNodeSpace(worldPoint), this._anchorPointInPoints); 1696 }, 1697 1698 /** 1699 * Converts a local Point to world space coordinates.The result is in Points.<br/> 1700 * treating the returned/received node point as anchor relative. 1701 * @param {cc.Point} nodePoint 1702 * @return {cc.Point} 1703 */ 1704 convertToWorldSpaceAR:function (nodePoint) { 1705 var pt = cc.pAdd(nodePoint, this._anchorPointInPoints); 1706 return this.convertToWorldSpace(pt); 1707 }, 1708 1709 _convertToWindowSpace:function (nodePoint) { 1710 var worldPoint = this.convertToWorldSpace(nodePoint); 1711 return cc.Director.getInstance().convertToUI(worldPoint); 1712 }, 1713 1714 /** convenience methods which take a cc.Touch instead of cc.Point 1715 * @param {cc.Touch} touch 1716 * @return {cc.Point} 1717 */ 1718 convertTouchToNodeSpace:function (touch) { 1719 var point = touch.getLocation(); 1720 //TODO in canvas point don't convert to GL 1721 //point = cc.Director.getInstance().convertToGL(point); 1722 return this.convertToNodeSpace(point); 1723 }, 1724 1725 /** 1726 * converts a cc.Touch (world coordinates) into a local coordiante. This method is AR (Anchor Relative). 1727 * @param {cc.Touch}touch 1728 * @return {cc.Point} 1729 */ 1730 convertTouchToNodeSpaceAR:function (touch) { 1731 var point = touch.getLocation(); 1732 point = cc.Director.getInstance().convertToGL(point); 1733 return this.convertToNodeSpaceAR(point); 1734 }, 1735 1736 /** implement cc.Object's method (override me) 1737 * @param {Number} dt 1738 */ 1739 update:function (dt) { 1740 }, 1741 1742 updateTransform:function(){ 1743 // Recursively iterate over children 1744 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform); 1745 }, 1746 1747 /** 1748 * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB, 1749 * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. 1750 * This is a hack, and should be removed once JSB fixes the retain/release bug 1751 */ 1752 retain:function () { 1753 }, 1754 release:function () { 1755 } 1756 }); 1757 1758 /** 1759 * cc.Node's state callback type 1760 * @constant 1761 * @type Number 1762 */ 1763 cc.Node.StateCallbackType = {onEnter:1, onExit:2, cleanup:3, onEnterTransitionDidFinish:4, updateTransform:5, onExitTransitionDidStart:6, sortAllChildren:7}; 1764 1765 1766 /** 1767 * allocates and initializes a node. 1768 * @constructs 1769 * @return {cc.Node} 1770 * @example 1771 * // example 1772 * var node = cc.Node.create(); 1773 */ 1774 cc.Node.create = function () { 1775 return new cc.Node(); 1776 }; 1777 1778