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 * <p>cc.Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) ) <br/> 29 * 30 * cc.Sprite can be created with an image, or with a sub-rectangle of an image. <br/> 31 * 32 * If the parent or any of its ancestors is a cc.SpriteBatchNode then the following features/limitations are valid <br/> 33 * - Features when the parent is a cc.BatchNode: <br/> 34 * - MUCH faster rendering, specially if the cc.SpriteBatchNode has many children. All the children will be drawn in a single batch. <br/> 35 * 36 * - Limitations <br/> 37 * - Camera is not supported yet (eg: CCOrbitCamera action doesn't work) <br/> 38 * - GridBase actions are not supported (eg: CCLens, CCRipple, CCTwirl) <br/> 39 * - The Alias/Antialias property belongs to CCSpriteBatchNode, so you can't individually set the aliased property. <br/> 40 * - The Blending function property belongs to CCSpriteBatchNode, so you can't individually set the blending function property. <br/> 41 * - Parallax scroller is not supported, but can be simulated with a "proxy" sprite. <br/> 42 * 43 * If the parent is an standard cc.Node, then cc.Sprite behaves like any other cc.Node: <br/> 44 * - It supports blending functions <br/> 45 * - It supports aliasing / antialiasing <br/> 46 * - But the rendering will be slower: 1 draw per children. <br/> 47 * 48 * The default anchorPoint in cc.Sprite is (0.5, 0.5). </p> 49 * @class 50 * @extends cc.Node 51 * 52 * @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName The string which indicates a path to image file, e.g., "scene1/monster.png". 53 * @param {cc.Rect} [rect] Only the contents inside rect of pszFileName's texture will be applied for this sprite. 54 * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated. 55 * @example 56 * 57 * 1.Create a sprite with image path and rect 58 * var sprite1 = new cc.Sprite("res/HelloHTML5World.png"); 59 * var sprite2 = new cc.Sprite("res/HelloHTML5World.png",cc.rect(0,0,480,320)); 60 * 61 * 2.Create a sprite with a sprite frame name. Must add "#" before frame name. 62 * var sprite = new cc.Sprite('#grossini_dance_01.png'); 63 * 64 * 3.Create a sprite with a sprite frame 65 * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); 66 * var sprite = new cc.Sprite(spriteFrame); 67 * 68 * 4.Create a sprite with an existing texture contained in a CCTexture2D object 69 * After creation, the rect will be the size of the texture, and the offset will be (0,0). 70 * var texture = cc.textureCache.addImage("HelloHTML5World.png"); 71 * var sprite1 = new cc.Sprite(texture); 72 * var sprite2 = new cc.Sprite(texture, cc.rect(0,0,480,320)); 73 * 74 * @property {Boolean} dirty - Indicates whether the sprite needs to be updated. 75 * @property {Boolean} flippedX - Indicates whether or not the sprite is flipped on x axis. 76 * @property {Boolean} flippedY - Indicates whether or not the sprite is flipped on y axis. 77 * @property {Number} offsetX - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex. 78 * @property {Number} offsetY - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex. 79 * @property {Number} atlasIndex - The index used on the TextureAtlas. 80 * @property {cc.Texture2D} texture - Texture used to render the sprite. 81 * @property {Boolean} textureRectRotated - <@readonly> Indicate whether the texture rectangle is rotated. 82 * @property {cc.TextureAtlas} textureAtlas - The weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode. 83 * @property {cc.SpriteBatchNode} batchNode - The batch node object if this sprite is rendered by cc.SpriteBatchNode. 84 * @property {cc.V3F_C4B_T2F_Quad} quad - <@readonly> The quad (tex coords, vertex coords and color) information. 85 */ 86 cc.Sprite = cc.Node.extend(/** @lends cc.Sprite# */{ 87 dirty:false, 88 atlasIndex:0, 89 textureAtlas:null, 90 91 _batchNode:null, 92 _recursiveDirty:null, //Whether all of the sprite's children needs to be updated 93 _hasChildren:null, //Whether the sprite contains children 94 _shouldBeHidden:false, //should not be drawn because one of the ancestors is not visible 95 _transformToBatch:null, 96 97 // 98 // Data used when the sprite is self-rendered 99 // 100 _blendFunc:null, //It's required for CCTextureProtocol inheritance 101 _texture:null, //cc.Texture2D object that is used to render the sprite 102 103 // 104 // Shared data 105 // 106 // texture 107 _rect:null, //Rectangle of cc.Texture2D 108 _rectRotated:false, //Whether the texture is rotated 109 110 // Offset Position (used by Zwoptex) 111 _offsetPosition:null, // absolute 112 _unflippedOffsetPositionFromCenter:null, 113 114 _opacityModifyRGB:false, 115 116 // image is flipped 117 _flippedX:false, //Whether the sprite is flipped horizontally or not. 118 _flippedY:false, //Whether the sprite is flipped vertically or not. 119 120 _textureLoaded:false, 121 _className:"Sprite", 122 123 ctor: function (fileName, rect, rotated) { 124 var self = this; 125 cc.Node.prototype.ctor.call(self); 126 self._shouldBeHidden = false; 127 self._offsetPosition = cc.p(0, 0); 128 self._unflippedOffsetPositionFromCenter = cc.p(0, 0); 129 self._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; 130 self._rect = cc.rect(0, 0, 0, 0); 131 132 self._softInit(fileName, rect, rotated); 133 }, 134 135 onEnter: function () { 136 this._super(); 137 if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) { 138 this._renderCmd.updateBuffer(); 139 } 140 }, 141 142 cleanup: function () { 143 if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) { 144 this._renderCmd.freeBuffer(); 145 } 146 this._super(); 147 }, 148 149 /** 150 * Returns whether the texture have been loaded 151 * @returns {boolean} 152 */ 153 textureLoaded:function(){ 154 return this._textureLoaded; 155 }, 156 157 /** 158 * Add a event listener for texture loaded event. 159 * @param {Function} callback 160 * @param {Object} target 161 * @deprecated since 3.1, please use addEventListener instead 162 */ 163 addLoadedEventListener:function(callback, target){ 164 this.addEventListener("load", callback, target); 165 }, 166 167 /** 168 * Returns whether or not the Sprite needs to be updated in the Atlas 169 * @return {Boolean} True if the sprite needs to be updated in the Atlas, false otherwise. 170 */ 171 isDirty:function () { 172 return this.dirty; 173 }, 174 175 /** 176 * Makes the sprite to be updated in the Atlas. 177 * @param {Boolean} bDirty 178 */ 179 setDirty:function (bDirty) { 180 this.dirty = bDirty; 181 }, 182 183 /** 184 * Returns whether or not the texture rectangle is rotated. 185 * @return {Boolean} 186 */ 187 isTextureRectRotated:function () { 188 return this._rectRotated; 189 }, 190 191 /** 192 * Returns the index used on the TextureAtlas. 193 * @return {Number} 194 */ 195 getAtlasIndex:function () { 196 return this.atlasIndex; 197 }, 198 199 /** 200 * Sets the index used on the TextureAtlas. 201 * @warning Don't modify this value unless you know what you are doing 202 * @param {Number} atlasIndex 203 */ 204 setAtlasIndex:function (atlasIndex) { 205 this.atlasIndex = atlasIndex; 206 }, 207 208 /** 209 * Returns the rect of the cc.Sprite in points 210 * @return {cc.Rect} 211 */ 212 getTextureRect:function () { 213 return cc.rect(this._rect); 214 }, 215 216 /** 217 * Returns the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode 218 * @return {cc.TextureAtlas} 219 */ 220 getTextureAtlas:function () { 221 return this.textureAtlas; 222 }, 223 224 /** 225 * Sets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode 226 * @param {cc.TextureAtlas} textureAtlas 227 */ 228 setTextureAtlas:function (textureAtlas) { 229 this.textureAtlas = textureAtlas; 230 }, 231 232 /** 233 * Returns the offset position of the sprite. Calculated automatically by editors like Zwoptex. 234 * @return {cc.Point} 235 */ 236 getOffsetPosition:function () { 237 return cc.p(this._offsetPosition); 238 }, 239 240 _getOffsetX: function () { 241 return this._offsetPosition.x; 242 }, 243 _getOffsetY: function () { 244 return this._offsetPosition.y; 245 }, 246 247 /** 248 * Returns the blend function 249 * @return {cc.BlendFunc} 250 */ 251 getBlendFunc:function () { 252 return this._blendFunc; 253 }, 254 255 /** 256 * Initializes a sprite with a SpriteFrame. The texture and rect in SpriteFrame will be applied on this sprite.<br/> 257 * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself, 258 * @param {cc.SpriteFrame} spriteFrame A CCSpriteFrame object. It should includes a valid texture and a rect 259 * @return {Boolean} true if the sprite is initialized properly, false otherwise. 260 */ 261 initWithSpriteFrame:function (spriteFrame) { 262 cc.assert(spriteFrame, cc._LogInfos.Sprite_initWithSpriteFrame); 263 264 if(!spriteFrame.textureLoaded()){ 265 //add event listener 266 this._textureLoaded = false; 267 spriteFrame.addEventListener("load", this._renderCmd._spriteFrameLoadedCallback, this); 268 } 269 270 //TODO 271 var rotated = cc._renderType === cc.game.RENDER_TYPE_CANVAS ? false : spriteFrame._rotated; 272 var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect(), rotated); 273 this.setSpriteFrame(spriteFrame); 274 275 return ret; 276 }, 277 278 /** 279 * Initializes a sprite with a sprite frame name. <br/> 280 * A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name. <br/> 281 * If the cc.SpriteFrame doesn't exist it will raise an exception. <br/> 282 * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. 283 * @param {String} spriteFrameName A key string that can fected a valid cc.SpriteFrame from cc.SpriteFrameCache 284 * @return {Boolean} true if the sprite is initialized properly, false otherwise. 285 * @example 286 * var sprite = new cc.Sprite(); 287 * sprite.initWithSpriteFrameName("grossini_dance_01.png"); 288 */ 289 initWithSpriteFrameName:function (spriteFrameName) { 290 cc.assert(spriteFrameName, cc._LogInfos.Sprite_initWithSpriteFrameName); 291 var frame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName); 292 cc.assert(frame, spriteFrameName + cc._LogInfos.Sprite_initWithSpriteFrameName1); 293 return this.initWithSpriteFrame(frame); 294 }, 295 296 /** 297 * Tell the sprite to use batch node render. 298 * @param {cc.SpriteBatchNode} batchNode 299 */ 300 useBatchNode:function (batchNode) { 301 this.textureAtlas = batchNode.getTextureAtlas(); // weak ref 302 this._batchNode = batchNode; 303 }, 304 305 /** 306 * <p> 307 * set the vertex rect.<br/> 308 * It will be called internally by setTextureRect. <br/> 309 * Useful if you want to create 2x images from SD images in Retina Display. <br/> 310 * Do not call it manually. Use setTextureRect instead. <br/> 311 * (override this method to generate "double scale" sprites) 312 * </p> 313 * @param {cc.Rect} rect 314 */ 315 setVertexRect:function (rect) { 316 var locRect = this._rect; 317 locRect.x = rect.x; 318 locRect.y = rect.y; 319 locRect.width = rect.width; 320 locRect.height = rect.height; 321 }, 322 323 /** 324 * Sort all children of this sprite node. 325 * @override 326 */ 327 sortAllChildren:function () { 328 if (this._reorderChildDirty) { 329 var _children = this._children; 330 331 cc.Node.prototype.sortAllChildren.call(this); 332 333 if (this._batchNode) { 334 this._arrayMakeObjectsPerformSelector(_children, cc.Node._stateCallbackType.sortAllChildren); 335 } 336 337 //don't need to check children recursively, that's done in visit of each child 338 this._reorderChildDirty = false; 339 } 340 341 }, 342 343 /** 344 * Reorders a child according to a new z value. (override cc.Node ) 345 * @param {cc.Node} child 346 * @param {Number} zOrder 347 * @override 348 */ 349 reorderChild:function (child, zOrder) { 350 cc.assert(child, cc._LogInfos.Sprite_reorderChild_2); 351 if(this._children.indexOf(child) === -1){ 352 cc.log(cc._LogInfos.Sprite_reorderChild); 353 return; 354 } 355 356 if (zOrder === child.zIndex) 357 return; 358 359 if (this._batchNode && !this._reorderChildDirty) { 360 this._setReorderChildDirtyRecursively(); 361 this._batchNode.reorderBatch(true); 362 } 363 cc.Node.prototype.reorderChild.call(this, child, zOrder); 364 }, 365 366 /** 367 * Removes a child from the sprite. 368 * @param child 369 * @param cleanup whether or not cleanup all running actions 370 * @override 371 */ 372 removeChild:function (child, cleanup) { 373 if (this._batchNode) 374 this._batchNode.removeSpriteFromAtlas(child); 375 cc.Node.prototype.removeChild.call(this, child, cleanup); 376 }, 377 378 /** 379 * Sets whether the sprite is visible or not. 380 * @param {Boolean} visible 381 * @override 382 */ 383 setVisible:function (visible) { 384 cc.Node.prototype.setVisible.call(this, visible); 385 this._renderCmd.setDirtyRecursively(true); 386 }, 387 388 /** 389 * Removes all children from the container. 390 * @param cleanup whether or not cleanup all running actions 391 * @override 392 */ 393 removeAllChildren:function (cleanup) { 394 var locChildren = this._children, locBatchNode = this._batchNode; 395 if (locBatchNode && locChildren != null) { 396 for (var i = 0, len = locChildren.length; i < len; i++) 397 locBatchNode.removeSpriteFromAtlas(locChildren[i]); 398 } 399 400 cc.Node.prototype.removeAllChildren.call(this, cleanup); 401 this._hasChildren = false; 402 }, 403 404 // 405 // cc.Node property overloads 406 // 407 408 /** 409 * Sets whether ignore anchor point for positioning 410 * @param {Boolean} relative 411 * @override 412 */ 413 ignoreAnchorPointForPosition:function (relative) { 414 if(this._batchNode){ 415 cc.log(cc._LogInfos.Sprite_ignoreAnchorPointForPosition); 416 return; 417 } 418 cc.Node.prototype.ignoreAnchorPointForPosition.call(this, relative); 419 }, 420 421 /** 422 * Sets whether the sprite should be flipped horizontally or not. 423 * @param {Boolean} flippedX true if the sprite should be flipped horizontally, false otherwise. 424 */ 425 setFlippedX:function (flippedX) { 426 if (this._flippedX !== flippedX) { 427 this._flippedX = flippedX; 428 this.setTextureRect(this._rect, this._rectRotated, this._contentSize); 429 this.setNodeDirty(true); 430 } 431 }, 432 433 /** 434 * Sets whether the sprite should be flipped vertically or not. 435 * @param {Boolean} flippedY true if the sprite should be flipped vertically, false otherwise. 436 */ 437 setFlippedY:function (flippedY) { 438 if (this._flippedY !== flippedY) { 439 this._flippedY = flippedY; 440 this.setTextureRect(this._rect, this._rectRotated, this._contentSize); 441 this.setNodeDirty(true); 442 } 443 }, 444 445 /** 446 * <p> 447 * Returns the flag which indicates whether the sprite is flipped horizontally or not. <br/> 448 * <br/> 449 * It only flips the texture of the sprite, and not the texture of the sprite's children. <br/> 450 * Also, flipping the texture doesn't alter the anchorPoint. <br/> 451 * If you want to flip the anchorPoint too, and/or to flip the children too use: <br/> 452 * sprite.setScaleX(sprite.getScaleX() * -1); <p/> 453 * @return {Boolean} true if the sprite is flipped horizontally, false otherwise. 454 */ 455 isFlippedX:function () { 456 return this._flippedX; 457 }, 458 459 /** 460 * <p> 461 * Return the flag which indicates whether the sprite is flipped vertically or not. <br/> 462 * <br/> 463 * It only flips the texture of the sprite, and not the texture of the sprite's children. <br/> 464 * Also, flipping the texture doesn't alter the anchorPoint. <br/> 465 * If you want to flip the anchorPoint too, and/or to flip the children too use: <br/> 466 * sprite.setScaleY(sprite.getScaleY() * -1); <p/> 467 * @return {Boolean} true if the sprite is flipped vertically, false otherwise. 468 */ 469 isFlippedY:function () { 470 return this._flippedY; 471 }, 472 473 // 474 // RGBA protocol 475 // 476 /** 477 * Sets whether opacity modify color or not. 478 * @function 479 * @param {Boolean} modify 480 */ 481 setOpacityModifyRGB: function (modify) { 482 if (this._opacityModifyRGB !== modify) { 483 this._opacityModifyRGB = modify; 484 this._renderCmd._setColorDirty(); 485 } 486 }, 487 488 /** 489 * Returns whether opacity modify color or not. 490 * @return {Boolean} 491 */ 492 isOpacityModifyRGB:function () { 493 return this._opacityModifyRGB; 494 }, 495 496 // Animation 497 498 /** 499 * Changes the display frame with animation name and index.<br/> 500 * The animation name will be get from the CCAnimationCache 501 * @param {String} animationName 502 * @param {Number} frameIndex 503 */ 504 setDisplayFrameWithAnimationName:function (animationName, frameIndex) { 505 cc.assert(animationName, cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_3); 506 507 var cache = cc.animationCache.getAnimation(animationName); 508 if(!cache){ 509 cc.log(cc._LogInfos.Sprite_setDisplayFrameWithAnimationName); 510 return; 511 } 512 var animFrame = cache.getFrames()[frameIndex]; 513 if(!animFrame){ 514 cc.log(cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_2); 515 return; 516 } 517 this.setSpriteFrame(animFrame.getSpriteFrame()); 518 }, 519 520 /** 521 * Returns the batch node object if this sprite is rendered by cc.SpriteBatchNode 522 * @returns {cc.SpriteBatchNode|null} The cc.SpriteBatchNode object if this sprite is rendered by cc.SpriteBatchNode, null if the sprite isn't used batch node. 523 */ 524 getBatchNode:function () { 525 return this._batchNode; 526 }, 527 528 _setReorderChildDirtyRecursively:function () { 529 //only set parents flag the first time 530 if (!this._reorderChildDirty) { 531 this._reorderChildDirty = true; 532 var pNode = this._parent; 533 while (pNode && pNode !== this._batchNode) { 534 pNode._setReorderChildDirtyRecursively(); 535 pNode = pNode.parent; 536 } 537 } 538 }, 539 540 // CCTextureProtocol 541 /** 542 * Returns the texture of the sprite node 543 * @returns {cc.Texture2D} 544 */ 545 getTexture:function () { 546 return this._texture; 547 }, 548 549 _softInit: function (fileName, rect, rotated) { 550 if (fileName === undefined) 551 cc.Sprite.prototype.init.call(this); 552 else if (cc.isString(fileName)) { 553 if (fileName[0] === "#") { 554 // Init with a sprite frame name 555 var frameName = fileName.substr(1, fileName.length - 1); 556 var spriteFrame = cc.spriteFrameCache.getSpriteFrame(frameName); 557 if (spriteFrame) 558 this.initWithSpriteFrame(spriteFrame); 559 else 560 cc.log("%s does not exist", fileName); 561 } else { 562 // Init with filename and rect 563 cc.Sprite.prototype.init.call(this, fileName, rect); 564 } 565 } else if (typeof fileName === "object") { 566 if (fileName instanceof cc.Texture2D) { 567 // Init with texture and rect 568 this.initWithTexture(fileName, rect, rotated); 569 } else if (fileName instanceof cc.SpriteFrame) { 570 // Init with a sprite frame 571 this.initWithSpriteFrame(fileName); 572 } else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) { 573 // Init with a canvas or image element 574 var texture2d = new cc.Texture2D(); 575 texture2d.initWithElement(fileName); 576 texture2d.handleLoadedTexture(); 577 this.initWithTexture(texture2d); 578 } 579 } 580 }, 581 582 /** 583 * Returns the quad (tex coords, vertex coords and color) information. 584 * @return {cc.V3F_C4B_T2F_Quad|null} Returns a cc.V3F_C4B_T2F_Quad object when render mode is WebGL, returns null when render mode is Canvas. 585 */ 586 getQuad:function () { 587 return this._renderCmd.getQuad(); 588 }, 589 590 /** 591 * conforms to cc.TextureProtocol protocol 592 * @function 593 * @param {Number|cc.BlendFunc} src 594 * @param {Number} dst 595 */ 596 setBlendFunc: function (src, dst) { 597 var locBlendFunc = this._blendFunc; 598 if (dst === undefined) { 599 locBlendFunc.src = src.src; 600 locBlendFunc.dst = src.dst; 601 } else { 602 locBlendFunc.src = src; 603 locBlendFunc.dst = dst; 604 } 605 this._renderCmd.updateBlendFunc(locBlendFunc); 606 }, 607 608 /** 609 * Initializes an empty sprite with nothing init.<br/> 610 * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. 611 * @function 612 * @return {Boolean} 613 */ 614 init: function () { 615 var _t = this; 616 if (arguments.length > 0) 617 return _t.initWithFile(arguments[0], arguments[1]); 618 619 cc.Node.prototype.init.call(_t); 620 _t.dirty = _t._recursiveDirty = false; 621 622 _t._blendFunc.src = cc.BLEND_SRC; 623 _t._blendFunc.dst = cc.BLEND_DST; 624 625 _t.texture = null; 626 _t._flippedX = _t._flippedY = false; 627 628 // default transform anchor: center 629 _t.anchorX = 0.5; 630 _t.anchorY = 0.5; 631 632 // zwoptex default values 633 _t._offsetPosition.x = 0; 634 _t._offsetPosition.y = 0; 635 _t._hasChildren = false; 636 637 this._renderCmd._init(); 638 // updated in "useSelfRender" 639 // Atlas: TexCoords 640 _t.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0)); 641 return true; 642 }, 643 644 /** 645 * <p> 646 * Initializes a sprite with an image filename.<br/> 647 * 648 * This method will find pszFilename from local file system, load its content to CCTexture2D,<br/> 649 * then use CCTexture2D to create a sprite.<br/> 650 * After initialization, the rect used will be the size of the image. The offset will be (0,0).<br/> 651 * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. 652 * </p> 653 * @param {String} filename The path to an image file in local file system 654 * @param {cc.Rect} rect The rectangle assigned the content area from texture. 655 * @return {Boolean} true if the sprite is initialized properly, false otherwise. 656 */ 657 initWithFile:function (filename, rect) { 658 cc.assert(filename, cc._LogInfos.Sprite_initWithFile); 659 660 var tex = cc.textureCache.getTextureForKey(filename); 661 if (!tex) { 662 tex = cc.textureCache.addImage(filename); 663 return this.initWithTexture(tex, rect || cc.rect(0, 0, tex._contentSize.width, tex._contentSize.height)); 664 } else { 665 if (!rect) { 666 var size = tex.getContentSize(); 667 rect = cc.rect(0, 0, size.width, size.height); 668 } 669 return this.initWithTexture(tex, rect); 670 } 671 }, 672 673 /** 674 * Initializes a sprite with a texture and a rect in points, optionally rotated. <br/> 675 * After initialization, the rect used will be the size of the texture, and the offset will be (0,0).<br/> 676 * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. 677 * @function 678 * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites. 679 * @param {cc.Rect} [rect] Only the contents inside rect of this texture will be applied for this sprite. 680 * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated. 681 * @param {Boolean} [counterclockwise=true] Whether or not the texture rectangle rotation is counterclockwise (texture package is counterclockwise, spine is clockwise). 682 * @return {Boolean} true if the sprite is initialized properly, false otherwise. 683 */ 684 initWithTexture: function (texture, rect, rotated, counterclockwise) { 685 var _t = this; 686 cc.assert(arguments.length !== 0, cc._LogInfos.CCSpriteBatchNode_initWithTexture); 687 688 rotated = rotated || false; 689 texture = this._renderCmd._handleTextureForRotatedTexture(texture, rect, rotated, counterclockwise); 690 691 if (!cc.Node.prototype.init.call(_t)) 692 return false; 693 694 _t._batchNode = null; 695 _t._recursiveDirty = false; 696 _t.dirty = false; 697 _t._opacityModifyRGB = true; 698 699 _t._blendFunc.src = cc.BLEND_SRC; 700 _t._blendFunc.dst = cc.BLEND_DST; 701 702 _t._flippedX = _t._flippedY = false; 703 704 // default transform anchor: center 705 _t.setAnchorPoint(0.5, 0.5); 706 707 // zwoptex default values 708 _t._offsetPosition.x = 0; 709 _t._offsetPosition.y = 0; 710 _t._hasChildren = false; 711 712 this._renderCmd._init(); 713 714 var locTextureLoaded = texture.isLoaded(); 715 _t._textureLoaded = locTextureLoaded; 716 717 if (!locTextureLoaded) { 718 _t._rectRotated = rotated; 719 if (rect) { 720 _t._rect.x = rect.x; 721 _t._rect.y = rect.y; 722 _t._rect.width = rect.width; 723 _t._rect.height = rect.height; 724 } 725 if(_t.texture) 726 _t.texture.removeEventListener("load", _t); 727 texture.addEventListener("load", _t._renderCmd._textureLoadedCallback, _t); 728 _t.setTexture(texture); 729 return true; 730 } 731 732 if (!rect) 733 rect = cc.rect(0, 0, texture.width, texture.height); 734 735 this._renderCmd._checkTextureBoundary(texture, rect, rotated); 736 737 _t.setTexture(texture); 738 _t.setTextureRect(rect, rotated); 739 740 // by default use "Self Render". 741 // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" 742 _t.setBatchNode(null); 743 return true; 744 }, 745 746 /** 747 * Updates the texture rect of the CCSprite in points. 748 * @function 749 * @param {cc.Rect} rect a rect of texture 750 * @param {Boolean} [rotated] Whether or not the texture is rotated 751 * @param {cc.Size} [untrimmedSize] The original pixels size of the texture 752 * @param {Boolean} [needConvert] contentScaleFactor switch 753 */ 754 setTextureRect: function (rect, rotated, untrimmedSize, needConvert) { 755 var _t = this; 756 _t._rectRotated = rotated || false; 757 _t.setContentSize(untrimmedSize || rect); 758 759 _t.setVertexRect(rect); 760 _t._renderCmd._setTextureCoords(rect, needConvert); 761 762 var relativeOffsetX = _t._unflippedOffsetPositionFromCenter.x, relativeOffsetY = _t._unflippedOffsetPositionFromCenter.y; 763 if (_t._flippedX) 764 relativeOffsetX = -relativeOffsetX; 765 if (_t._flippedY) 766 relativeOffsetY = -relativeOffsetY; 767 var locRect = _t._rect; 768 _t._offsetPosition.x = relativeOffsetX + (_t._contentSize.width - locRect.width) / 2; 769 _t._offsetPosition.y = relativeOffsetY + (_t._contentSize.height - locRect.height) / 2; 770 771 // rendering using batch node 772 if (_t._batchNode) { 773 // update dirty, don't update _recursiveDirty 774 _t.dirty = true; 775 } else { 776 // self rendering 777 // Atlas: Vertex 778 this._renderCmd._resetForBatchNode(); 779 } 780 }, 781 782 // BatchNode methods 783 /** 784 * Updates the quad according the the rotation, position, scale values. 785 * @function 786 */ 787 updateTransform: function(){ 788 this._renderCmd.updateTransform(); 789 }, 790 791 /** 792 * Add child to sprite (override cc.Node) 793 * @function 794 * @param {cc.Sprite} child 795 * @param {Number} localZOrder child's zOrder 796 * @param {number|String} [tag] child's tag 797 * @override 798 */ 799 addChild: function (child, localZOrder, tag) { 800 cc.assert(child, cc._LogInfos.CCSpriteBatchNode_addChild_2); 801 802 if (localZOrder == null) 803 localZOrder = child._localZOrder; 804 if (tag == null) 805 tag = child.tag; 806 807 if(this._renderCmd._setBatchNodeForAddChild(child)){ 808 //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check 809 cc.Node.prototype.addChild.call(this, child, localZOrder, tag); 810 this._hasChildren = true; 811 } 812 }, 813 814 // Frames 815 /** 816 * Sets a new sprite frame to the sprite. 817 * @function 818 * @param {cc.SpriteFrame|String} newFrame 819 */ 820 setSpriteFrame: function (newFrame) { 821 var _t = this; 822 if(cc.isString(newFrame)){ 823 newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame); 824 cc.assert(newFrame, cc._LogInfos.Sprite_setSpriteFrame) 825 } 826 827 this.setNodeDirty(true); 828 829 var frameOffset = newFrame.getOffset(); 830 _t._unflippedOffsetPositionFromCenter.x = frameOffset.x; 831 _t._unflippedOffsetPositionFromCenter.y = frameOffset.y; 832 833 // update rect 834 var pNewTexture = newFrame.getTexture(); 835 var locTextureLoaded = newFrame.textureLoaded(); 836 if (!locTextureLoaded) { 837 _t._textureLoaded = false; 838 newFrame.addEventListener("load", function (sender) { 839 _t._textureLoaded = true; 840 var locNewTexture = sender.getTexture(); 841 if (locNewTexture !== _t._texture) 842 _t._setTexture(locNewTexture); 843 _t.setTextureRect(sender.getRect(), sender.isRotated(), sender.getOriginalSize()); 844 _t.dispatchEvent("load"); 845 _t.setColor(_t._realColor); 846 }, _t); 847 } else { 848 _t._textureLoaded = true; 849 // update texture before updating texture rect 850 if (pNewTexture !== _t._texture) { 851 _t._setTexture(pNewTexture); 852 _t.setColor(_t._realColor); 853 } 854 _t.setTextureRect(newFrame.getRect(), newFrame.isRotated(), newFrame.getOriginalSize()); 855 } 856 this._renderCmd._updateForSetSpriteFrame(pNewTexture); 857 }, 858 859 /** 860 * Sets a new display frame to the sprite. 861 * @param {cc.SpriteFrame|String} newFrame 862 * @deprecated 863 */ 864 setDisplayFrame: function(newFrame){ 865 cc.log(cc._LogInfos.Sprite_setDisplayFrame); 866 this.setSpriteFrame(newFrame); 867 }, 868 869 /** 870 * Returns whether or not a cc.SpriteFrame is being displayed 871 * @function 872 * @param {cc.SpriteFrame} frame 873 * @return {Boolean} 874 */ 875 isFrameDisplayed: function(frame){ 876 return this._renderCmd.isFrameDisplayed(frame); 877 }, 878 879 /** 880 * Returns the current displayed frame. 881 * @deprecated since 3.4, please use getSpriteFrame instead 882 * @return {cc.SpriteFrame} 883 */ 884 displayFrame: function () { 885 return this.getSpriteFrame(); 886 }, 887 888 /** 889 * Returns the current displayed frame. 890 * @return {cc.SpriteFrame} 891 */ 892 getSpriteFrame: function () { 893 return new cc.SpriteFrame(this._texture, 894 cc.rectPointsToPixels(this._rect), 895 this._rectRotated, 896 cc.pointPointsToPixels(this._unflippedOffsetPositionFromCenter), 897 cc.sizePointsToPixels(this._contentSize)); 898 }, 899 900 /** 901 * Sets the batch node to sprite 902 * @function 903 * @param {cc.SpriteBatchNode|null} spriteBatchNode 904 * @example 905 * var batch = new cc.SpriteBatchNode("Images/grossini_dance_atlas.png", 15); 906 * var sprite = new cc.Sprite(batch.texture, cc.rect(0, 0, 57, 57)); 907 * batch.addChild(sprite); 908 * layer.addChild(batch); 909 */ 910 setBatchNode:function (spriteBatchNode) { 911 var _t = this; 912 _t._batchNode = spriteBatchNode; // weak reference 913 914 // self render 915 if (!_t._batchNode) { 916 _t.atlasIndex = cc.Sprite.INDEX_NOT_INITIALIZED; 917 _t.textureAtlas = null; 918 _t._recursiveDirty = false; 919 _t.dirty = false; 920 921 this._renderCmd._resetForBatchNode(); 922 } else { 923 // using batch 924 _t._transformToBatch = cc.affineTransformIdentity(); 925 _t.textureAtlas = _t._batchNode.getTextureAtlas(); // weak ref 926 } 927 }, 928 929 // CCTextureProtocol 930 /** 931 * Sets the texture of sprite 932 * @function 933 * @param {cc.Texture2D|String} texture 934 */ 935 setTexture: function (texture) { 936 if(!texture) 937 return this._renderCmd._setTexture(null); 938 939 //CCSprite.cpp 327 and 338 940 var isFileName = cc.isString(texture); 941 942 if(isFileName) 943 texture = cc.textureCache.addImage(texture); 944 945 if(texture._textureLoaded){ 946 this._setTexture(texture, isFileName); 947 this.setColor(this._realColor); 948 this._textureLoaded = true; 949 }else{ 950 this._renderCmd._setTexture(null); 951 texture.addEventListener("load", function(){ 952 this._setTexture(texture, isFileName); 953 this.setColor(this._realColor); 954 this._textureLoaded = true; 955 }, this); 956 } 957 }, 958 959 _setTexture: function(texture, change){ 960 this._renderCmd._setTexture(texture); 961 if(change) 962 this._changeRectWithTexture(texture); 963 }, 964 965 _changeRectWithTexture: function(texture){ 966 var contentSize = texture._contentSize; 967 var rect = cc.rect( 968 0, 0, 969 contentSize.width, contentSize.height 970 ); 971 this.setTextureRect(rect); 972 }, 973 974 _createRenderCmd: function(){ 975 if(cc._renderType === cc.game.RENDER_TYPE_CANVAS) 976 return new cc.Sprite.CanvasRenderCmd(this); 977 else 978 return new cc.Sprite.WebGLRenderCmd(this); 979 } 980 }); 981 982 /** 983 * Create a sprite with image path or frame name or texture or spriteFrame. 984 * @deprecated since v3.0, please use new construction instead 985 * @see cc.Sprite 986 * @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName The string which indicates a path to image file, e.g., "scene1/monster.png". 987 * @param {cc.Rect} rect Only the contents inside rect of pszFileName's texture will be applied for this sprite. 988 * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated. 989 * @return {cc.Sprite} A valid sprite object 990 */ 991 cc.Sprite.create = function (fileName, rect, rotated) { 992 return new cc.Sprite(fileName, rect, rotated); 993 }; 994 995 /** 996 * @deprecated since v3.0, please use new construction instead 997 * @see cc.Sprite 998 * @function 999 */ 1000 cc.Sprite.createWithTexture = cc.Sprite.create; 1001 1002 /** 1003 * @deprecated since v3.0, please use new construction instead 1004 * @see cc.Sprite 1005 * @function 1006 */ 1007 cc.Sprite.createWithSpriteFrameName = cc.Sprite.create; 1008 1009 /** 1010 * @deprecated since v3.0, please use new construction instead 1011 * @see cc.Sprite 1012 * @function 1013 */ 1014 cc.Sprite.createWithSpriteFrame = cc.Sprite.create; 1015 /** 1016 * cc.Sprite invalid index on the cc.SpriteBatchNode 1017 * @constant 1018 * @type {Number} 1019 */ 1020 cc.Sprite.INDEX_NOT_INITIALIZED = -1; 1021 1022 cc.EventHelper.prototype.apply(cc.Sprite.prototype); 1023 1024 cc.assert(cc.isFunction(cc._tmp.PrototypeSprite), cc._LogInfos.MissingFile, "SpritesPropertyDefine.js"); 1025 cc._tmp.PrototypeSprite(); 1026 delete cc._tmp.PrototypeSprite; 1027