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