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 // ideas taken from: 28 // . The ocean spray in your face [Jeff Lander] 29 // http://www.double.co.nz/dust/col0798.pdf 30 // . Building an Advanced Particle System [John van der Burg] 31 // http://www.gamasutra.com/features/20000623/vanderburg_01.htm 32 // . LOVE game engine 33 // http://love2d.org/ 34 // 35 // 36 // Radius mode support, from 71 squared 37 // http://particledesigner.71squared.com/ 38 // 39 // IMPORTANT: Particle Designer is supported by cocos2d, but 40 // 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d, 41 // cocos2d uses a another approach, but the results are almost identical. 42 // 43 44 45 // tCCPositionType 46 // possible types of particle positions 47 48 49 /** 50 * Structure that contains the values of each particle 51 * @Class 52 * @Construct 53 * @param {cc.Point} [pos=cc.p(0,0)] Position of particle 54 * @param {cc.Point} [startPos=cc.p(0,0)] 55 * @param {cc.Color} [color= cc.color(0, 0, 0, 255)] 56 * @param {cc.Color} [deltaColor=cc.color(0, 0, 0, 255)] 57 * @param {cc.Size} [size=0] 58 * @param {cc.Size} [deltaSize=0] 59 * @param {Number} [rotation=0] 60 * @param {Number} [deltaRotation=0] 61 * @param {Number} [timeToLive=0] 62 * @param {Number} [atlasIndex=0] 63 * @param {cc.Particle.ModeA} [modeA=] 64 * @param {cc.Particle.ModeA} [modeB=] 65 */ 66 cc.Particle = function (pos, startPos, color, deltaColor, size, deltaSize, rotation, deltaRotation, timeToLive, atlasIndex, modeA, modeB) { 67 this.pos = pos ? pos : cc.p(0,0); 68 this.startPos = startPos ? startPos : cc.p(0,0); 69 this.color = color ? color : {r:0, g: 0, b:0, a:255}; 70 this.deltaColor = deltaColor ? deltaColor : {r:0, g: 0, b:0, a:255} ; 71 this.size = size || 0; 72 this.deltaSize = deltaSize || 0; 73 this.rotation = rotation || 0; 74 this.deltaRotation = deltaRotation || 0; 75 this.timeToLive = timeToLive || 0; 76 this.atlasIndex = atlasIndex || 0; 77 this.modeA = modeA ? modeA : new cc.Particle.ModeA(); 78 this.modeB = modeB ? modeB : new cc.Particle.ModeB(); 79 this.isChangeColor = false; 80 this.drawPos = cc.p(0, 0); 81 }; 82 83 /** 84 * Mode A: gravity, direction, radial accel, tangential accel 85 * @Class 86 * @Construct 87 * @param {cc.Point} dir direction of particle 88 * @param {Number} radialAccel 89 * @param {Number} tangentialAccel 90 */ 91 cc.Particle.ModeA = function (dir, radialAccel, tangentialAccel) { 92 this.dir = dir ? dir : cc.p(0,0); 93 this.radialAccel = radialAccel || 0; 94 this.tangentialAccel = tangentialAccel || 0; 95 }; 96 97 /** 98 * Mode B: radius mode 99 * @Class 100 * @Construct 101 * @param {Number} angle 102 * @param {Number} degreesPerSecond 103 * @param {Number} radius 104 * @param {Number} deltaRadius 105 */ 106 cc.Particle.ModeB = function (angle, degreesPerSecond, radius, deltaRadius) { 107 this.angle = angle || 0; 108 this.degreesPerSecond = degreesPerSecond || 0; 109 this.radius = radius || 0; 110 this.deltaRadius = deltaRadius || 0; 111 }; 112 113 /** 114 * Array of Point instances used to optimize particle updates 115 */ 116 cc.Particle.TemporaryPoints = [ 117 cc.p(), 118 cc.p(), 119 cc.p(), 120 cc.p() 121 ]; 122 123 /** 124 * <p> 125 * Particle System base class. <br/> 126 * Attributes of a Particle System:<br/> 127 * - emission rate of the particles<br/> 128 * - Gravity Mode (Mode A): <br/> 129 * - gravity <br/> 130 * - direction <br/> 131 * - speed +- variance <br/> 132 * - tangential acceleration +- variance<br/> 133 * - radial acceleration +- variance<br/> 134 * - Radius Mode (Mode B): <br/> 135 * - startRadius +- variance <br/> 136 * - endRadius +- variance <br/> 137 * - rotate +- variance <br/> 138 * - Properties common to all modes: <br/> 139 * - life +- life variance <br/> 140 * - start spin +- variance <br/> 141 * - end spin +- variance <br/> 142 * - start size +- variance <br/> 143 * - end size +- variance <br/> 144 * - start color +- variance <br/> 145 * - end color +- variance <br/> 146 * - life +- variance <br/> 147 * - blending function <br/> 148 * - texture <br/> 149 * <br/> 150 * cocos2d also supports particles generated by Particle Designer (http://particledesigner.71squared.com/).<br/> 151 * 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d, <br/> 152 * cocos2d uses a another approach, but the results are almost identical.<br/> 153 * cocos2d supports all the variables used by Particle Designer plus a bit more: <br/> 154 * - spinning particles (supported when using ParticleSystem) <br/> 155 * - tangential acceleration (Gravity mode) <br/> 156 * - radial acceleration (Gravity mode) <br/> 157 * - radius direction (Radius mode) (Particle Designer supports outwards to inwards direction only) <br/> 158 * It is possible to customize any of the above mentioned properties in runtime. Example: <br/> 159 * </p> 160 * @class 161 * @extends cc.Node 162 * 163 * @property {Boolean} opacityModifyRGB - Indicate whether the alpha value modify color. 164 * @property {cc.SpriteBatchNode} batchNode - Weak reference to the sprite batch node. 165 * @property {Boolean} active - <@readonly> Indicate whether the particle system is activated. 166 * @property {Number} shapeType - ShapeType of ParticleSystem : cc.ParticleSystem.BALL_SHAPE | cc.ParticleSystem.STAR_SHAPE. 167 * @property {Number} atlasIndex - Index of system in batch node array. 168 * @property {Number} particleCount - Current quantity of particles that are being simulated. 169 * @property {Number} duration - How many seconds the emitter wil run. -1 means 'forever' 170 * @property {cc.Point} sourcePos - Source position of the emitter. 171 * @property {cc.Point} posVar - Variation of source position. 172 * @property {Number} life - Life of each particle setter. 173 * @property {Number} lifeVar - Variation of life. 174 * @property {Number} angle - Angle of each particle setter. 175 * @property {Number} angleVar - Variation of angle of each particle setter. 176 * @property {Number} startSize - Start size in pixels of each particle. 177 * @property {Number} startSizeVar - Variation of start size in pixels. 178 * @property {Number} endSize - End size in pixels of each particle. 179 * @property {Number} endSizeVar - Variation of end size in pixels. 180 * @property {Number} startSpin - Start angle of each particle. 181 * @property {Number} startSpinVar - Variation of start angle. 182 * @property {Number} endSpin - End angle of each particle. 183 * @property {Number} endSpinVar - Variation of end angle. 184 * @property {cc.Point} gravity - Gravity of the emitter. 185 * @property {cc.Point} speed - Speed of the emitter. 186 * @property {cc.Point} speedVar - Variation of the speed. 187 * @property {Number} tangentialAccel - Tangential acceleration of each particle. Only available in 'Gravity' mode. 188 * @property {Number} tangentialAccelVar - Variation of the tangential acceleration. 189 * @property {Number} tangentialAccel - Radial acceleration of each particle. Only available in 'Gravity' mode. 190 * @property {Number} tangentialAccelVar - Variation of the radial acceleration. 191 * @property {Boolean} rotationIsDir - Indicate whether the rotation of each particle equals to its direction. Only available in 'Gravity' mode. 192 * @property {Number} startRadius - Starting radius of the particles. Only available in 'Radius' mode. 193 * @property {Number} startRadiusVar - Variation of the starting radius. 194 * @property {Number} endRadius - Ending radius of the particles. Only available in 'Radius' mode. 195 * @property {Number} endRadiusVar - Variation of the ending radius. 196 * @property {Number} rotatePerS - Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. 197 * @property {Number} rotatePerSVar - Variation of the degress to rotate a particle around the source pos per second. 198 * @property {cc.Color} startColor - Start color of each particle. 199 * @property {cc.Color} startColorVar - Variation of the start color. 200 * @property {cc.Color} endColor - Ending color of each particle. 201 * @property {cc.Color} endColorVar - Variation of the end color. 202 * @property {Number} emissionRate - Emission rate of the particles. 203 * @property {Number} emitterMode - Emitter modes: CCParticleSystem.MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration; CCParticleSystem.MODE_RADIUS: uses radius movement + rotation. 204 * @property {Number} positionType - Particles movement type: cc.ParticleSystem.TYPE_FREE | cc.ParticleSystem.TYPE_GROUPED. 205 * @property {Number} totalParticles - Maximum particles of the system. 206 * @property {Boolean} autoRemoveOnFinish - Indicate whether the node will be auto-removed when it has no particles left. 207 * @property {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture - Texture of Particle System. 208 * 209 * @example 210 * emitter.radialAccel = 15; 211 * emitter.startSpin = 0; 212 */ 213 cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ 214 _className:"ParticleSystem", 215 //***********variables************* 216 _plistFile: "", 217 //! time elapsed since the start of the system (in seconds) 218 _elapsed: 0, 219 _dontTint: false, 220 221 // Different modes 222 //! Mode A:Gravity + Tangential Accel + Radial Accel 223 modeA: null, 224 //! Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) 225 modeB: null, 226 227 //private POINTZERO for ParticleSystem 228 _pointZeroForParticle: cc.p(0, 0), 229 230 //! Array of particles 231 _particles: null, 232 233 // color modulate 234 // BOOL colorModulate; 235 236 //! How many particles can be emitted per second 237 _emitCounter: 0, 238 //! particle idx 239 _particleIdx: 0, 240 241 _batchNode: null, 242 atlasIndex: 0, 243 244 //true if scaled or rotated 245 _transformSystemDirty: false, 246 _allocatedParticles: 0, 247 248 _isActive: false, 249 particleCount: 0, 250 duration: 0, 251 _sourcePosition: null, 252 _posVar: null, 253 life: 0, 254 lifeVar: 0, 255 angle: 0, 256 angleVar: 0, 257 startSize: 0, 258 startSizeVar: 0, 259 endSize: 0, 260 endSizeVar: 0, 261 _startColor: null, 262 _startColorVar: null, 263 _endColor: null, 264 _endColorVar: null, 265 startSpin: 0, 266 startSpinVar: 0, 267 endSpin: 0, 268 endSpinVar: 0, 269 emissionRate: 0, 270 _totalParticles: 0, 271 _texture: null, 272 _blendFunc: null, 273 _opacityModifyRGB: false, 274 positionType: null, 275 autoRemoveOnFinish: false, 276 emitterMode: 0, 277 278 _textureLoaded: null, 279 280 /** 281 * <p> return the string found by key in dict. <br/> 282 * This plist files can be create manually or with Particle Designer:<br/> 283 * http://particledesigner.71squared.com/<br/> 284 * </p> 285 * Constructor of cc.ParticleSystem 286 * @param {String|Number} plistFile 287 */ 288 ctor:function (plistFile) { 289 cc.Node.prototype.ctor.call(this); 290 this.emitterMode = cc.ParticleSystem.MODE_GRAVITY; 291 this.modeA = new cc.ParticleSystem.ModeA(); 292 this.modeB = new cc.ParticleSystem.ModeB(); 293 this._blendFunc = {src:cc.BLEND_SRC, dst:cc.BLEND_DST}; 294 295 this._particles = []; 296 this._sourcePosition = cc.p(0, 0); 297 this._posVar = cc.p(0, 0); 298 299 this._startColor = cc.color(255, 255, 255, 255); 300 this._startColorVar = cc.color(255, 255, 255, 255); 301 this._endColor = cc.color(255, 255, 255, 255); 302 this._endColorVar = cc.color(255, 255, 255, 255); 303 304 this._plistFile = ""; 305 this._elapsed = 0; 306 this._dontTint = false; 307 this._pointZeroForParticle = cc.p(0, 0); 308 this._emitCounter = 0; 309 this._particleIdx = 0; 310 this._batchNode = null; 311 this.atlasIndex = 0; 312 313 this._transformSystemDirty = false; 314 this._allocatedParticles = 0; 315 this._isActive = false; 316 this.particleCount = 0; 317 this.duration = 0; 318 this.life = 0; 319 this.lifeVar = 0; 320 this.angle = 0; 321 this.angleVar = 0; 322 this.startSize = 0; 323 this.startSizeVar = 0; 324 this.endSize = 0; 325 this.endSizeVar = 0; 326 327 this.startSpin = 0; 328 this.startSpinVar = 0; 329 this.endSpin = 0; 330 this.endSpinVar = 0; 331 this.emissionRate = 0; 332 this._totalParticles = 0; 333 this._texture = null; 334 this._opacityModifyRGB = false; 335 this.positionType = cc.ParticleSystem.TYPE_FREE; 336 this.autoRemoveOnFinish = false; 337 338 this._textureLoaded = true; 339 340 if (!plistFile || cc.isNumber(plistFile)) { 341 var ton = plistFile || 100; 342 this.setDrawMode(cc.ParticleSystem.TEXTURE_MODE); 343 this.initWithTotalParticles(ton); 344 } else if (cc.isString(plistFile)) { 345 this.initWithFile(plistFile); 346 } else if (cc.isObject(plistFile)) { 347 this.initWithDictionary(plistFile, ""); 348 } 349 }, 350 351 _createRenderCmd: function(){ 352 if(cc._renderType === cc.game.RENDER_TYPE_CANVAS) 353 return new cc.ParticleSystem.CanvasRenderCmd(this); 354 else 355 return new cc.ParticleSystem.WebGLRenderCmd(this); 356 }, 357 358 /** 359 * This is a hack function for performance, it's only available on Canvas mode. <br/> 360 * It's very expensive to change color on Canvas mode, so if set it to true, particle system will ignore the changing color operation. 361 * @param {boolean} ignore 362 */ 363 ignoreColor: function(ignore){ 364 this._dontTint = ignore; 365 }, 366 367 /** 368 * <p> initializes the texture with a rectangle measured Points<br/> 369 * pointRect should be in Texture coordinates, not pixel coordinates 370 * </p> 371 * @param {cc.Rect} pointRect 372 */ 373 initTexCoordsWithRect:function (pointRect) { 374 this._renderCmd.initTexCoordsWithRect(pointRect); 375 }, 376 377 /** 378 * return weak reference to the cc.SpriteBatchNode that renders the cc.Sprite 379 * @return {cc.ParticleBatchNode} 380 */ 381 getBatchNode:function () { 382 return this._batchNode; 383 }, 384 385 /** 386 * set weak reference to the cc.SpriteBatchNode that renders the cc.Sprite 387 * @param {cc.ParticleBatchNode} batchNode 388 */ 389 setBatchNode:function (batchNode) { 390 this._renderCmd.setBatchNode(batchNode); 391 }, 392 393 /** 394 * return index of system in batch node array 395 * @return {Number} 396 */ 397 getAtlasIndex:function () { 398 return this.atlasIndex; 399 }, 400 401 /** 402 * set index of system in batch node array 403 * @param {Number} atlasIndex 404 */ 405 setAtlasIndex:function (atlasIndex) { 406 this.atlasIndex = atlasIndex; 407 }, 408 409 /** 410 * Return DrawMode of ParticleSystem (Canvas Mode only) 411 * @return {Number} 412 */ 413 getDrawMode:function () { 414 return this._renderCmd.getDrawMode(); 415 }, 416 417 /** 418 * DrawMode of ParticleSystem setter (Canvas Mode only) 419 * @param {Number} drawMode 420 */ 421 setDrawMode:function (drawMode) { 422 this._renderCmd.setDrawMode(drawMode); 423 }, 424 425 /** 426 * Return ShapeType of ParticleSystem (Canvas Mode only) 427 * @return {Number} 428 */ 429 getShapeType:function () { 430 return this._renderCmd.getShapeType(); 431 }, 432 433 /** 434 * ShapeType of ParticleSystem setter (Canvas Mode only) 435 * @param {Number} shapeType 436 */ 437 setShapeType:function (shapeType) { 438 this._renderCmd.setShapeType(shapeType); 439 }, 440 441 /** 442 * Return ParticleSystem is active 443 * @return {Boolean} 444 */ 445 isActive:function () { 446 return this._isActive; 447 }, 448 449 /** 450 * Quantity of particles that are being simulated at the moment 451 * @return {Number} 452 */ 453 getParticleCount:function () { 454 return this.particleCount; 455 }, 456 457 /** 458 * Quantity of particles setter 459 * @param {Number} particleCount 460 */ 461 setParticleCount:function (particleCount) { 462 this.particleCount = particleCount; 463 }, 464 465 /** 466 * How many seconds the emitter wil run. -1 means 'forever' 467 * @return {Number} 468 */ 469 getDuration:function () { 470 return this.duration; 471 }, 472 473 /** 474 * set run seconds of the emitter 475 * @param {Number} duration 476 */ 477 setDuration:function (duration) { 478 this.duration = duration; 479 }, 480 481 /** 482 * Return sourcePosition of the emitter 483 * @return {cc.Point | Object} 484 */ 485 getSourcePosition:function () { 486 return {x: this._sourcePosition.x, y: this._sourcePosition.y}; 487 }, 488 489 /** 490 * sourcePosition of the emitter setter 491 * @param sourcePosition 492 */ 493 setSourcePosition:function (sourcePosition) { 494 this._sourcePosition = sourcePosition; 495 }, 496 497 /** 498 * Return Position variance of the emitter 499 * @return {cc.Point | Object} 500 */ 501 getPosVar:function () { 502 return {x: this._posVar.x, y: this._posVar.y}; 503 }, 504 505 /** 506 * Position variance of the emitter setter 507 * @param {cc.Point} posVar 508 */ 509 setPosVar:function (posVar) { 510 this._posVar = posVar; 511 }, 512 513 /** 514 * Return life of each particle 515 * @return {Number} 516 */ 517 getLife:function () { 518 return this.life; 519 }, 520 521 /** 522 * life of each particle setter 523 * @param {Number} life 524 */ 525 setLife:function (life) { 526 this.life = life; 527 }, 528 529 /** 530 * Return life variance of each particle 531 * @return {Number} 532 */ 533 getLifeVar:function () { 534 return this.lifeVar; 535 }, 536 537 /** 538 * life variance of each particle setter 539 * @param {Number} lifeVar 540 */ 541 setLifeVar:function (lifeVar) { 542 this.lifeVar = lifeVar; 543 }, 544 545 /** 546 * Return angle of each particle 547 * @return {Number} 548 */ 549 getAngle:function () { 550 return this.angle; 551 }, 552 553 /** 554 * angle of each particle setter 555 * @param {Number} angle 556 */ 557 setAngle:function (angle) { 558 this.angle = angle; 559 }, 560 561 /** 562 * Return angle variance of each particle 563 * @return {Number} 564 */ 565 getAngleVar:function () { 566 return this.angleVar; 567 }, 568 569 /** 570 * angle variance of each particle setter 571 * @param angleVar 572 */ 573 setAngleVar:function (angleVar) { 574 this.angleVar = angleVar; 575 }, 576 577 // mode A 578 /** 579 * Return Gravity of emitter 580 * @return {cc.Point} 581 */ 582 getGravity:function () { 583 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 584 cc.log("cc.ParticleBatchNode.getGravity() : Particle Mode should be Gravity"); 585 var locGravity = this.modeA.gravity; 586 return cc.p(locGravity.x, locGravity.y); 587 }, 588 589 /** 590 * Gravity of emitter setter 591 * @param {cc.Point} gravity 592 */ 593 setGravity:function (gravity) { 594 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 595 cc.log("cc.ParticleBatchNode.setGravity() : Particle Mode should be Gravity"); 596 this.modeA.gravity = gravity; 597 }, 598 599 /** 600 * Return Speed of each particle 601 * @return {Number} 602 */ 603 getSpeed:function () { 604 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 605 cc.log("cc.ParticleBatchNode.getSpeed() : Particle Mode should be Gravity"); 606 return this.modeA.speed; 607 }, 608 609 /** 610 * Speed of each particle setter 611 * @param {Number} speed 612 */ 613 setSpeed:function (speed) { 614 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 615 cc.log("cc.ParticleBatchNode.setSpeed() : Particle Mode should be Gravity"); 616 this.modeA.speed = speed; 617 }, 618 619 /** 620 * return speed variance of each particle. Only available in 'Gravity' mode. 621 * @return {Number} 622 */ 623 getSpeedVar:function () { 624 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 625 cc.log("cc.ParticleBatchNode.getSpeedVar() : Particle Mode should be Gravity"); 626 return this.modeA.speedVar; 627 }, 628 629 /** 630 * speed variance of each particle setter. Only available in 'Gravity' mode. 631 * @param {Number} speedVar 632 */ 633 setSpeedVar:function (speedVar) { 634 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 635 cc.log("cc.ParticleBatchNode.setSpeedVar() : Particle Mode should be Gravity"); 636 this.modeA.speedVar = speedVar; 637 }, 638 639 /** 640 * Return tangential acceleration of each particle. Only available in 'Gravity' mode. 641 * @return {Number} 642 */ 643 getTangentialAccel:function () { 644 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 645 cc.log("cc.ParticleBatchNode.getTangentialAccel() : Particle Mode should be Gravity"); 646 return this.modeA.tangentialAccel; 647 }, 648 649 /** 650 * Tangential acceleration of each particle setter. Only available in 'Gravity' mode. 651 * @param {Number} tangentialAccel 652 */ 653 setTangentialAccel:function (tangentialAccel) { 654 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 655 cc.log("cc.ParticleBatchNode.setTangentialAccel() : Particle Mode should be Gravity"); 656 this.modeA.tangentialAccel = tangentialAccel; 657 }, 658 659 /** 660 * Return tangential acceleration variance of each particle. Only available in 'Gravity' mode. 661 * @return {Number} 662 */ 663 getTangentialAccelVar:function () { 664 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 665 cc.log("cc.ParticleBatchNode.getTangentialAccelVar() : Particle Mode should be Gravity"); 666 return this.modeA.tangentialAccelVar; 667 }, 668 669 /** 670 * tangential acceleration variance of each particle setter. Only available in 'Gravity' mode. 671 * @param {Number} tangentialAccelVar 672 */ 673 setTangentialAccelVar:function (tangentialAccelVar) { 674 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 675 cc.log("cc.ParticleBatchNode.setTangentialAccelVar() : Particle Mode should be Gravity"); 676 this.modeA.tangentialAccelVar = tangentialAccelVar; 677 }, 678 679 /** 680 * Return radial acceleration of each particle. Only available in 'Gravity' mode. 681 * @return {Number} 682 */ 683 getRadialAccel:function () { 684 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 685 cc.log("cc.ParticleBatchNode.getRadialAccel() : Particle Mode should be Gravity"); 686 return this.modeA.radialAccel; 687 }, 688 689 /** 690 * radial acceleration of each particle setter. Only available in 'Gravity' mode. 691 * @param {Number} radialAccel 692 */ 693 setRadialAccel:function (radialAccel) { 694 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 695 cc.log("cc.ParticleBatchNode.setRadialAccel() : Particle Mode should be Gravity"); 696 this.modeA.radialAccel = radialAccel; 697 }, 698 699 /** 700 * Return radial acceleration variance of each particle. Only available in 'Gravity' mode. 701 * @return {Number} 702 */ 703 getRadialAccelVar:function () { 704 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 705 cc.log("cc.ParticleBatchNode.getRadialAccelVar() : Particle Mode should be Gravity"); 706 return this.modeA.radialAccelVar; 707 }, 708 709 /** 710 * radial acceleration variance of each particle setter. Only available in 'Gravity' mode. 711 * @param {Number} radialAccelVar 712 */ 713 setRadialAccelVar:function (radialAccelVar) { 714 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 715 cc.log("cc.ParticleBatchNode.setRadialAccelVar() : Particle Mode should be Gravity"); 716 this.modeA.radialAccelVar = radialAccelVar; 717 }, 718 719 /** 720 * get the rotation of each particle to its direction Only available in 'Gravity' mode. 721 * @returns {boolean} 722 */ 723 getRotationIsDir: function(){ 724 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 725 cc.log("cc.ParticleBatchNode.getRotationIsDir() : Particle Mode should be Gravity"); 726 return this.modeA.rotationIsDir; 727 }, 728 729 /** 730 * set the rotation of each particle to its direction Only available in 'Gravity' mode. 731 * @param {boolean} t 732 */ 733 setRotationIsDir: function(t){ 734 if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) 735 cc.log("cc.ParticleBatchNode.setRotationIsDir() : Particle Mode should be Gravity"); 736 this.modeA.rotationIsDir = t; 737 }, 738 739 // mode B 740 /** 741 * Return starting radius of the particles. Only available in 'Radius' mode. 742 * @return {Number} 743 */ 744 getStartRadius:function () { 745 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 746 cc.log("cc.ParticleBatchNode.getStartRadius() : Particle Mode should be Radius"); 747 return this.modeB.startRadius; 748 }, 749 750 /** 751 * starting radius of the particles setter. Only available in 'Radius' mode. 752 * @param {Number} startRadius 753 */ 754 setStartRadius:function (startRadius) { 755 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 756 cc.log("cc.ParticleBatchNode.setStartRadius() : Particle Mode should be Radius"); 757 this.modeB.startRadius = startRadius; 758 }, 759 760 /** 761 * Return starting radius variance of the particles. Only available in 'Radius' mode. 762 * @return {Number} 763 */ 764 getStartRadiusVar:function () { 765 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 766 cc.log("cc.ParticleBatchNode.getStartRadiusVar() : Particle Mode should be Radius"); 767 return this.modeB.startRadiusVar; 768 }, 769 770 /** 771 * starting radius variance of the particles setter. Only available in 'Radius' mode. 772 * @param {Number} startRadiusVar 773 */ 774 setStartRadiusVar:function (startRadiusVar) { 775 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 776 cc.log("cc.ParticleBatchNode.setStartRadiusVar() : Particle Mode should be Radius"); 777 this.modeB.startRadiusVar = startRadiusVar; 778 }, 779 780 /** 781 * Return ending radius of the particles. Only available in 'Radius' mode. 782 * @return {Number} 783 */ 784 getEndRadius:function () { 785 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 786 cc.log("cc.ParticleBatchNode.getEndRadius() : Particle Mode should be Radius"); 787 return this.modeB.endRadius; 788 }, 789 790 /** 791 * ending radius of the particles setter. Only available in 'Radius' mode. 792 * @param {Number} endRadius 793 */ 794 setEndRadius:function (endRadius) { 795 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 796 cc.log("cc.ParticleBatchNode.setEndRadius() : Particle Mode should be Radius"); 797 this.modeB.endRadius = endRadius; 798 }, 799 800 /** 801 * Return ending radius variance of the particles. Only available in 'Radius' mode. 802 * @return {Number} 803 */ 804 getEndRadiusVar:function () { 805 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 806 cc.log("cc.ParticleBatchNode.getEndRadiusVar() : Particle Mode should be Radius"); 807 return this.modeB.endRadiusVar; 808 }, 809 810 /** 811 * ending radius variance of the particles setter. Only available in 'Radius' mode. 812 * @param endRadiusVar 813 */ 814 setEndRadiusVar:function (endRadiusVar) { 815 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 816 cc.log("cc.ParticleBatchNode.setEndRadiusVar() : Particle Mode should be Radius"); 817 this.modeB.endRadiusVar = endRadiusVar; 818 }, 819 820 /** 821 * get Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. 822 * @return {Number} 823 */ 824 getRotatePerSecond:function () { 825 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 826 cc.log("cc.ParticleBatchNode.getRotatePerSecond() : Particle Mode should be Radius"); 827 return this.modeB.rotatePerSecond; 828 }, 829 830 /** 831 * set Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. 832 * @param {Number} degrees 833 */ 834 setRotatePerSecond:function (degrees) { 835 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 836 cc.log("cc.ParticleBatchNode.setRotatePerSecond() : Particle Mode should be Radius"); 837 this.modeB.rotatePerSecond = degrees; 838 }, 839 840 /** 841 * Return Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. 842 * @return {Number} 843 */ 844 getRotatePerSecondVar:function () { 845 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 846 cc.log("cc.ParticleBatchNode.getRotatePerSecondVar() : Particle Mode should be Radius"); 847 return this.modeB.rotatePerSecondVar; 848 }, 849 850 /** 851 * Variance in degrees for rotatePerSecond setter. Only available in 'Radius' mode. 852 * @param degrees 853 */ 854 setRotatePerSecondVar:function (degrees) { 855 if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) 856 cc.log("cc.ParticleBatchNode.setRotatePerSecondVar() : Particle Mode should be Radius"); 857 this.modeB.rotatePerSecondVar = degrees; 858 }, 859 ////////////////////////////////////////////////////////////////////////// 860 861 //don't use a transform matrix, this is faster 862 setScale:function (scale, scaleY) { 863 this._transformSystemDirty = true; 864 cc.Node.prototype.setScale.call(this, scale, scaleY); 865 }, 866 867 setRotation:function (newRotation) { 868 this._transformSystemDirty = true; 869 cc.Node.prototype.setRotation.call(this, newRotation); 870 }, 871 872 setScaleX:function (newScaleX) { 873 this._transformSystemDirty = true; 874 cc.Node.prototype.setScaleX.call(this, newScaleX); 875 }, 876 877 setScaleY:function (newScaleY) { 878 this._transformSystemDirty = true; 879 cc.Node.prototype.setScaleY.call(this, newScaleY); 880 }, 881 882 /** 883 * get start size in pixels of each particle 884 * @return {Number} 885 */ 886 getStartSize:function () { 887 return this.startSize; 888 }, 889 890 /** 891 * set start size in pixels of each particle 892 * @param {Number} startSize 893 */ 894 setStartSize:function (startSize) { 895 this.startSize = startSize; 896 }, 897 898 /** 899 * get size variance in pixels of each particle 900 * @return {Number} 901 */ 902 getStartSizeVar:function () { 903 return this.startSizeVar; 904 }, 905 906 /** 907 * set size variance in pixels of each particle 908 * @param {Number} startSizeVar 909 */ 910 setStartSizeVar:function (startSizeVar) { 911 this.startSizeVar = startSizeVar; 912 }, 913 914 /** 915 * get end size in pixels of each particle 916 * @return {Number} 917 */ 918 getEndSize:function () { 919 return this.endSize; 920 }, 921 922 /** 923 * set end size in pixels of each particle 924 * @param endSize 925 */ 926 setEndSize:function (endSize) { 927 this.endSize = endSize; 928 }, 929 930 /** 931 * get end size variance in pixels of each particle 932 * @return {Number} 933 */ 934 getEndSizeVar:function () { 935 return this.endSizeVar; 936 }, 937 938 /** 939 * set end size variance in pixels of each particle 940 * @param {Number} endSizeVar 941 */ 942 setEndSizeVar:function (endSizeVar) { 943 this.endSizeVar = endSizeVar; 944 }, 945 946 /** 947 * set start color of each particle 948 * @return {cc.Color} 949 */ 950 getStartColor:function () { 951 return cc.color(this._startColor.r, this._startColor.g, this._startColor.b, this._startColor.a); 952 }, 953 954 /** 955 * get start color of each particle 956 * @param {cc.Color} startColor 957 */ 958 setStartColor:function (startColor) { 959 this._startColor = cc.color(startColor); 960 }, 961 962 /** 963 * get start color variance of each particle 964 * @return {cc.Color} 965 */ 966 getStartColorVar:function () { 967 return cc.color(this._startColorVar.r, this._startColorVar.g, this._startColorVar.b, this._startColorVar.a); 968 }, 969 970 /** 971 * set start color variance of each particle 972 * @param {cc.Color} startColorVar 973 */ 974 setStartColorVar:function (startColorVar) { 975 this._startColorVar = cc.color(startColorVar); 976 }, 977 978 /** 979 * get end color and end color variation of each particle 980 * @return {cc.Color} 981 */ 982 getEndColor:function () { 983 return cc.color(this._endColor.r, this._endColor.g, this._endColor.b, this._endColor.a); 984 }, 985 986 /** 987 * set end color and end color variation of each particle 988 * @param {cc.Color} endColor 989 */ 990 setEndColor:function (endColor) { 991 this._endColor = cc.color(endColor); 992 }, 993 994 /** 995 * get end color variance of each particle 996 * @return {cc.Color} 997 */ 998 getEndColorVar:function () { 999 return cc.color(this._endColorVar.r, this._endColorVar.g, this._endColorVar.b, this._endColorVar.a); 1000 }, 1001 1002 /** 1003 * set end color variance of each particle 1004 * @param {cc.Color} endColorVar 1005 */ 1006 setEndColorVar:function (endColorVar) { 1007 this._endColorVar = cc.color(endColorVar); 1008 }, 1009 1010 /** 1011 * get initial angle of each particle 1012 * @return {Number} 1013 */ 1014 getStartSpin:function () { 1015 return this.startSpin; 1016 }, 1017 1018 /** 1019 * set initial angle of each particle 1020 * @param {Number} startSpin 1021 */ 1022 setStartSpin:function (startSpin) { 1023 this.startSpin = startSpin; 1024 }, 1025 1026 /** 1027 * get initial angle variance of each particle 1028 * @return {Number} 1029 */ 1030 getStartSpinVar:function () { 1031 return this.startSpinVar; 1032 }, 1033 1034 /** 1035 * set initial angle variance of each particle 1036 * @param {Number} startSpinVar 1037 */ 1038 setStartSpinVar:function (startSpinVar) { 1039 this.startSpinVar = startSpinVar; 1040 }, 1041 1042 /** 1043 * get end angle of each particle 1044 * @return {Number} 1045 */ 1046 getEndSpin:function () { 1047 return this.endSpin; 1048 }, 1049 1050 /** 1051 * set end angle of each particle 1052 * @param {Number} endSpin 1053 */ 1054 setEndSpin:function (endSpin) { 1055 this.endSpin = endSpin; 1056 }, 1057 1058 /** 1059 * get end angle variance of each particle 1060 * @return {Number} 1061 */ 1062 getEndSpinVar:function () { 1063 return this.endSpinVar; 1064 }, 1065 1066 /** 1067 * set end angle variance of each particle 1068 * @param {Number} endSpinVar 1069 */ 1070 setEndSpinVar:function (endSpinVar) { 1071 this.endSpinVar = endSpinVar; 1072 }, 1073 1074 /** 1075 * get emission rate of the particles 1076 * @return {Number} 1077 */ 1078 getEmissionRate:function () { 1079 return this.emissionRate; 1080 }, 1081 1082 /** 1083 * set emission rate of the particles 1084 * @param {Number} emissionRate 1085 */ 1086 setEmissionRate:function (emissionRate) { 1087 this.emissionRate = emissionRate; 1088 }, 1089 1090 /** 1091 * get maximum particles of the system 1092 * @return {Number} 1093 */ 1094 getTotalParticles:function () { 1095 return this._totalParticles; 1096 }, 1097 1098 /** 1099 * set maximum particles of the system 1100 * @param {Number} tp totalParticles 1101 */ 1102 setTotalParticles:function (tp) { 1103 this._renderCmd.setTotalParticles(tp); 1104 }, 1105 1106 /** 1107 * get Texture of Particle System 1108 * @return {cc.Texture2D} 1109 */ 1110 getTexture:function () { 1111 return this._texture; 1112 }, 1113 1114 /** 1115 * set Texture of Particle System 1116 * @param {cc.Texture2D } texture 1117 */ 1118 setTexture:function (texture) { 1119 if(!texture) 1120 return; 1121 1122 if(texture.isLoaded()){ 1123 this.setTextureWithRect(texture, cc.rect(0, 0, texture.width, texture.height)); 1124 } else { 1125 this._textureLoaded = false; 1126 texture.addEventListener("load", function(sender){ 1127 this._textureLoaded = true; 1128 this.setTextureWithRect(sender, cc.rect(0, 0, sender.width, sender.height)); 1129 }, this); 1130 } 1131 }, 1132 1133 /** conforms to CocosNodeTexture protocol */ 1134 /** 1135 * get BlendFunc of Particle System 1136 * @return {cc.BlendFunc} 1137 */ 1138 getBlendFunc:function () { 1139 return this._blendFunc; 1140 }, 1141 1142 /** 1143 * set BlendFunc of Particle System 1144 * @param {Number} src 1145 * @param {Number} dst 1146 */ 1147 setBlendFunc:function (src, dst) { 1148 if (dst === undefined) { 1149 if (this._blendFunc !== src) { 1150 this._blendFunc = src; 1151 this._updateBlendFunc(); 1152 } 1153 } else { 1154 if (this._blendFunc.src !== src || this._blendFunc.dst !== dst) { 1155 this._blendFunc = {src:src, dst:dst}; 1156 this._updateBlendFunc(); 1157 } 1158 } 1159 }, 1160 1161 /** 1162 * does the alpha value modify color getter 1163 * @return {Boolean} 1164 */ 1165 isOpacityModifyRGB:function () { 1166 return this._opacityModifyRGB; 1167 }, 1168 1169 /** 1170 * does the alpha value modify color setter 1171 * @param newValue 1172 */ 1173 setOpacityModifyRGB:function (newValue) { 1174 this._opacityModifyRGB = newValue; 1175 }, 1176 1177 /** 1178 * <p>whether or not the particles are using blend additive.<br/> 1179 * If enabled, the following blending function will be used.<br/> 1180 * </p> 1181 * @return {Boolean} 1182 * @example 1183 * source blend function = GL_SRC_ALPHA; 1184 * dest blend function = GL_ONE; 1185 */ 1186 isBlendAdditive:function () { 1187 return (( this._blendFunc.src === cc.SRC_ALPHA && this._blendFunc.dst === cc.ONE) || (this._blendFunc.src === cc.ONE && this._blendFunc.dst === cc.ONE)); 1188 }, 1189 1190 /** 1191 * <p>whether or not the particles are using blend additive.<br/> 1192 * If enabled, the following blending function will be used.<br/> 1193 * </p> 1194 * @param {Boolean} isBlendAdditive 1195 */ 1196 setBlendAdditive:function (isBlendAdditive) { 1197 var locBlendFunc = this._blendFunc; 1198 if (isBlendAdditive) { 1199 locBlendFunc.src = cc.SRC_ALPHA; 1200 locBlendFunc.dst = cc.ONE; 1201 } else { 1202 this._renderCmd._setBlendAdditive(); 1203 } 1204 }, 1205 1206 /** 1207 * get particles movement type: Free or Grouped 1208 * @return {Number} 1209 */ 1210 getPositionType:function () { 1211 return this.positionType; 1212 }, 1213 1214 /** 1215 * set particles movement type: Free or Grouped 1216 * @param {Number} positionType 1217 */ 1218 setPositionType:function (positionType) { 1219 this.positionType = positionType; 1220 }, 1221 1222 /** 1223 * <p> return whether or not the node will be auto-removed when it has no particles left.<br/> 1224 * By default it is false.<br/> 1225 * </p> 1226 * @return {Boolean} 1227 */ 1228 isAutoRemoveOnFinish:function () { 1229 return this.autoRemoveOnFinish; 1230 }, 1231 1232 /** 1233 * <p> set whether or not the node will be auto-removed when it has no particles left.<br/> 1234 * By default it is false.<br/> 1235 * </p> 1236 * @param {Boolean} isAutoRemoveOnFinish 1237 */ 1238 setAutoRemoveOnFinish:function (isAutoRemoveOnFinish) { 1239 this.autoRemoveOnFinish = isAutoRemoveOnFinish; 1240 }, 1241 1242 /** 1243 * return kind of emitter modes 1244 * @return {Number} 1245 */ 1246 getEmitterMode:function () { 1247 return this.emitterMode; 1248 }, 1249 1250 /** 1251 * <p>Switch between different kind of emitter modes:<br/> 1252 * - CCParticleSystem.MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration<br/> 1253 * - CCParticleSystem.MODE_RADIUS: uses radius movement + rotation <br/> 1254 * </p> 1255 * @param {Number} emitterMode 1256 */ 1257 setEmitterMode:function (emitterMode) { 1258 this.emitterMode = emitterMode; 1259 }, 1260 1261 /** 1262 * initializes a cc.ParticleSystem 1263 */ 1264 init:function () { 1265 return this.initWithTotalParticles(150); 1266 }, 1267 1268 /** 1269 * <p> 1270 * initializes a CCParticleSystem from a plist file. <br/> 1271 * This plist files can be creted manually or with Particle Designer:<br/> 1272 * http://particledesigner.71squared.com/ 1273 * </p> 1274 * @param {String} plistFile 1275 * @return {boolean} 1276 */ 1277 initWithFile:function (plistFile) { 1278 this._plistFile = plistFile; 1279 var dict = cc.loader.getRes(plistFile); 1280 if(!dict){ 1281 cc.log("cc.ParticleSystem.initWithFile(): Particles: file not found"); 1282 return false; 1283 } 1284 1285 // XXX compute path from a path, should define a function somewhere to do it 1286 return this.initWithDictionary(dict, ""); 1287 }, 1288 1289 /** 1290 * return bounding box of particle system in world space 1291 * @return {cc.Rect} 1292 */ 1293 getBoundingBoxToWorld:function () { 1294 return cc.rect(0, 0, cc._canvas.width, cc._canvas.height); 1295 }, 1296 1297 /** 1298 * initializes a particle system from a NSDictionary and the path from where to load the png 1299 * @param {object} dictionary 1300 * @param {String} dirname 1301 * @return {Boolean} 1302 */ 1303 initWithDictionary:function (dictionary, dirname) { 1304 var ret = false; 1305 var buffer = null; 1306 var image = null; 1307 var locValueForKey = this._valueForKey; 1308 1309 var maxParticles = parseInt(locValueForKey("maxParticles", dictionary)); 1310 // self, not super 1311 if (this.initWithTotalParticles(maxParticles)) { 1312 // angle 1313 this.angle = parseFloat(locValueForKey("angle", dictionary)); 1314 this.angleVar = parseFloat(locValueForKey("angleVariance", dictionary)); 1315 1316 // duration 1317 this.duration = parseFloat(locValueForKey("duration", dictionary)); 1318 1319 // blend function 1320 this._blendFunc.src = parseInt(locValueForKey("blendFuncSource", dictionary)); 1321 this._blendFunc.dst = parseInt(locValueForKey("blendFuncDestination", dictionary)); 1322 1323 // color 1324 var locStartColor = this._startColor; 1325 locStartColor.r = parseFloat(locValueForKey("startColorRed", dictionary)) * 255; 1326 locStartColor.g = parseFloat(locValueForKey("startColorGreen", dictionary)) * 255; 1327 locStartColor.b = parseFloat(locValueForKey("startColorBlue", dictionary)) * 255; 1328 locStartColor.a = parseFloat(locValueForKey("startColorAlpha", dictionary)) * 255; 1329 1330 var locStartColorVar = this._startColorVar; 1331 locStartColorVar.r = parseFloat(locValueForKey("startColorVarianceRed", dictionary)) * 255; 1332 locStartColorVar.g = parseFloat(locValueForKey("startColorVarianceGreen", dictionary)) * 255; 1333 locStartColorVar.b = parseFloat(locValueForKey("startColorVarianceBlue", dictionary)) * 255; 1334 locStartColorVar.a = parseFloat(locValueForKey("startColorVarianceAlpha", dictionary)) * 255; 1335 1336 var locEndColor = this._endColor; 1337 locEndColor.r = parseFloat(locValueForKey("finishColorRed", dictionary)) * 255; 1338 locEndColor.g = parseFloat(locValueForKey("finishColorGreen", dictionary)) * 255; 1339 locEndColor.b = parseFloat(locValueForKey("finishColorBlue", dictionary)) * 255; 1340 locEndColor.a = parseFloat(locValueForKey("finishColorAlpha", dictionary)) * 255; 1341 1342 var locEndColorVar = this._endColorVar; 1343 locEndColorVar.r = parseFloat(locValueForKey("finishColorVarianceRed", dictionary)) * 255; 1344 locEndColorVar.g = parseFloat(locValueForKey("finishColorVarianceGreen", dictionary)) * 255; 1345 locEndColorVar.b = parseFloat(locValueForKey("finishColorVarianceBlue", dictionary)) * 255; 1346 locEndColorVar.a = parseFloat(locValueForKey("finishColorVarianceAlpha", dictionary)) * 255; 1347 1348 // particle size 1349 this.startSize = parseFloat(locValueForKey("startParticleSize", dictionary)); 1350 this.startSizeVar = parseFloat(locValueForKey("startParticleSizeVariance", dictionary)); 1351 this.endSize = parseFloat(locValueForKey("finishParticleSize", dictionary)); 1352 this.endSizeVar = parseFloat(locValueForKey("finishParticleSizeVariance", dictionary)); 1353 1354 // position 1355 this.setPosition(parseFloat(locValueForKey("sourcePositionx", dictionary)), 1356 parseFloat(locValueForKey("sourcePositiony", dictionary))); 1357 this._posVar.x = parseFloat(locValueForKey("sourcePositionVariancex", dictionary)); 1358 this._posVar.y = parseFloat(locValueForKey("sourcePositionVariancey", dictionary)); 1359 1360 // Spinning 1361 this.startSpin = parseFloat(locValueForKey("rotationStart", dictionary)); 1362 this.startSpinVar = parseFloat(locValueForKey("rotationStartVariance", dictionary)); 1363 this.endSpin = parseFloat(locValueForKey("rotationEnd", dictionary)); 1364 this.endSpinVar = parseFloat(locValueForKey("rotationEndVariance", dictionary)); 1365 1366 this.emitterMode = parseInt(locValueForKey("emitterType", dictionary)); 1367 1368 // Mode A: Gravity + tangential accel + radial accel 1369 if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) { 1370 var locModeA = this.modeA; 1371 // gravity 1372 locModeA.gravity.x = parseFloat(locValueForKey("gravityx", dictionary)); 1373 locModeA.gravity.y = parseFloat(locValueForKey("gravityy", dictionary)); 1374 1375 // speed 1376 locModeA.speed = parseFloat(locValueForKey("speed", dictionary)); 1377 locModeA.speedVar = parseFloat(locValueForKey("speedVariance", dictionary)); 1378 1379 // radial acceleration 1380 var pszTmp = locValueForKey("radialAcceleration", dictionary); 1381 locModeA.radialAccel = (pszTmp) ? parseFloat(pszTmp) : 0; 1382 1383 pszTmp = locValueForKey("radialAccelVariance", dictionary); 1384 locModeA.radialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0; 1385 1386 // tangential acceleration 1387 pszTmp = locValueForKey("tangentialAcceleration", dictionary); 1388 locModeA.tangentialAccel = (pszTmp) ? parseFloat(pszTmp) : 0; 1389 1390 pszTmp = locValueForKey("tangentialAccelVariance", dictionary); 1391 locModeA.tangentialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0; 1392 1393 // rotation is dir 1394 var locRotationIsDir = locValueForKey("rotationIsDir", dictionary).toLowerCase(); 1395 locModeA.rotationIsDir = (locRotationIsDir != null && (locRotationIsDir === "true" || locRotationIsDir === "1")); 1396 } else if (this.emitterMode === cc.ParticleSystem.MODE_RADIUS) { 1397 // or Mode B: radius movement 1398 var locModeB = this.modeB; 1399 locModeB.startRadius = parseFloat(locValueForKey("maxRadius", dictionary)); 1400 locModeB.startRadiusVar = parseFloat(locValueForKey("maxRadiusVariance", dictionary)); 1401 locModeB.endRadius = parseFloat(locValueForKey("minRadius", dictionary)); 1402 locModeB.endRadiusVar = 0; 1403 locModeB.rotatePerSecond = parseFloat(locValueForKey("rotatePerSecond", dictionary)); 1404 locModeB.rotatePerSecondVar = parseFloat(locValueForKey("rotatePerSecondVariance", dictionary)); 1405 } else { 1406 cc.log("cc.ParticleSystem.initWithDictionary(): Invalid emitterType in config file"); 1407 return false; 1408 } 1409 1410 // life span 1411 this.life = parseFloat(locValueForKey("particleLifespan", dictionary)); 1412 this.lifeVar = parseFloat(locValueForKey("particleLifespanVariance", dictionary)); 1413 1414 // emission Rate 1415 this.emissionRate = this._totalParticles / this.life; 1416 1417 //don't get the internal texture if a batchNode is used 1418 if (!this._batchNode) { 1419 // Set a compatible default for the alpha transfer 1420 this._opacityModifyRGB = false; 1421 1422 // texture 1423 // Try to get the texture from the cache 1424 var textureName = locValueForKey("textureFileName", dictionary); 1425 var imgPath = cc.path.changeBasename(this._plistFile, textureName); 1426 var tex = cc.textureCache.getTextureForKey(imgPath); 1427 1428 if (tex) { 1429 this.setTexture(tex); 1430 } else { 1431 var textureData = locValueForKey("textureImageData", dictionary); 1432 1433 if (!textureData || textureData.length === 0) { 1434 tex = cc.textureCache.addImage(imgPath); 1435 if (!tex) 1436 return false; 1437 this.setTexture(tex); 1438 } else { 1439 buffer = cc.unzipBase64AsArray(textureData, 1); 1440 if (!buffer) { 1441 cc.log("cc.ParticleSystem: error decoding or ungzipping textureImageData"); 1442 return false; 1443 } 1444 1445 var imageFormat = cc.getImageFormatByData(buffer); 1446 1447 if(imageFormat !== cc.FMT_TIFF && imageFormat !== cc.FMT_PNG){ 1448 cc.log("cc.ParticleSystem: unknown image format with Data"); 1449 return false; 1450 } 1451 1452 var canvasObj = document.createElement("canvas"); 1453 if(imageFormat === cc.FMT_PNG){ 1454 var myPngObj = new cc.PNGReader(buffer); 1455 myPngObj.render(canvasObj); 1456 } else { 1457 var myTIFFObj = cc.tiffReader; 1458 myTIFFObj.parseTIFF(buffer,canvasObj); 1459 } 1460 1461 cc.textureCache.cacheImage(imgPath, canvasObj); 1462 1463 var addTexture = cc.textureCache.getTextureForKey(imgPath); 1464 if(!addTexture) 1465 cc.log("cc.ParticleSystem.initWithDictionary() : error loading the texture"); 1466 this.setTexture(addTexture); 1467 } 1468 } 1469 } 1470 ret = true; 1471 } 1472 return ret; 1473 }, 1474 1475 /** 1476 * Initializes a system with a fixed number of particles 1477 * @param {Number} numberOfParticles 1478 * @return {Boolean} 1479 */ 1480 initWithTotalParticles:function (numberOfParticles) { 1481 this._totalParticles = numberOfParticles; 1482 1483 var i, locParticles = this._particles; 1484 locParticles.length = 0; 1485 for(i = 0; i< numberOfParticles; i++){ 1486 locParticles[i] = new cc.Particle(); 1487 } 1488 1489 if (!locParticles) { 1490 cc.log("Particle system: not enough memory"); 1491 return false; 1492 } 1493 this._allocatedParticles = numberOfParticles; 1494 1495 if (this._batchNode) 1496 for (i = 0; i < this._totalParticles; i++) 1497 locParticles[i].atlasIndex = i; 1498 1499 // default, active 1500 this._isActive = true; 1501 1502 // default blend function 1503 this._blendFunc.src = cc.BLEND_SRC; 1504 this._blendFunc.dst = cc.BLEND_DST; 1505 1506 // default movement type; 1507 this.positionType = cc.ParticleSystem.TYPE_FREE; 1508 1509 // by default be in mode A: 1510 this.emitterMode = cc.ParticleSystem.MODE_GRAVITY; 1511 1512 // default: modulate 1513 // XXX: not used 1514 // colorModulate = YES; 1515 this.autoRemoveOnFinish = false; 1516 1517 //for batchNode 1518 this._transformSystemDirty = false; 1519 1520 // udpate after action in run! 1521 this.scheduleUpdateWithPriority(1); 1522 this._renderCmd._initWithTotalParticles(numberOfParticles); 1523 return true; 1524 }, 1525 1526 /** 1527 * Unschedules the "update" method. 1528 * @function 1529 * @see scheduleUpdate(); 1530 */ 1531 destroyParticleSystem:function () { 1532 this.unscheduleUpdate(); 1533 }, 1534 1535 /** 1536 * Add a particle to the emitter 1537 * @return {Boolean} 1538 */ 1539 addParticle: function () { 1540 if (this.isFull()) 1541 return false; 1542 1543 var particle = this._renderCmd.addParticle(); 1544 this.initParticle(particle); 1545 ++this.particleCount; 1546 return true; 1547 }, 1548 1549 /** 1550 * Initializes a particle 1551 * @param {cc.Particle} particle 1552 */ 1553 initParticle:function (particle) { 1554 var locRandomMinus11 = cc.randomMinus1To1; 1555 // timeToLive 1556 // no negative life. prevent division by 0 1557 particle.timeToLive = this.life + this.lifeVar * locRandomMinus11(); 1558 particle.timeToLive = Math.max(0, particle.timeToLive); 1559 1560 // position 1561 particle.pos.x = this._sourcePosition.x + this._posVar.x * locRandomMinus11(); 1562 particle.pos.y = this._sourcePosition.y + this._posVar.y * locRandomMinus11(); 1563 1564 // Color 1565 var start, end; 1566 var locStartColor = this._startColor, locStartColorVar = this._startColorVar; 1567 var locEndColor = this._endColor, locEndColorVar = this._endColorVar; 1568 start = { 1569 r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 255), 1570 g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 255), 1571 b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 255), 1572 a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 255) 1573 }; 1574 end = { 1575 r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 255), 1576 g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 255), 1577 b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 255), 1578 a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 255) 1579 }; 1580 1581 particle.color = start; 1582 var locParticleDeltaColor = particle.deltaColor, locParticleTimeToLive = particle.timeToLive; 1583 locParticleDeltaColor.r = (end.r - start.r) / locParticleTimeToLive; 1584 locParticleDeltaColor.g = (end.g - start.g) / locParticleTimeToLive; 1585 locParticleDeltaColor.b = (end.b - start.b) / locParticleTimeToLive; 1586 locParticleDeltaColor.a = (end.a - start.a) / locParticleTimeToLive; 1587 1588 // size 1589 var startS = this.startSize + this.startSizeVar * locRandomMinus11(); 1590 startS = Math.max(0, startS); // No negative value 1591 1592 particle.size = startS; 1593 if (this.endSize === cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE) { 1594 particle.deltaSize = 0; 1595 } else { 1596 var endS = this.endSize + this.endSizeVar * locRandomMinus11(); 1597 endS = Math.max(0, endS); // No negative values 1598 particle.deltaSize = (endS - startS) / locParticleTimeToLive; 1599 } 1600 1601 // rotation 1602 var startA = this.startSpin + this.startSpinVar * locRandomMinus11(); 1603 var endA = this.endSpin + this.endSpinVar * locRandomMinus11(); 1604 particle.rotation = startA; 1605 particle.deltaRotation = (endA - startA) / locParticleTimeToLive; 1606 1607 // position 1608 if (this.positionType === cc.ParticleSystem.TYPE_FREE) 1609 particle.startPos = this.convertToWorldSpace(this._pointZeroForParticle); 1610 else if (this.positionType === cc.ParticleSystem.TYPE_RELATIVE){ 1611 particle.startPos.x = this._position.x; 1612 particle.startPos.y = this._position.y; 1613 } 1614 1615 // direction 1616 var a = cc.degreesToRadians(this.angle + this.angleVar * locRandomMinus11()); 1617 1618 // Mode Gravity: A 1619 if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) { 1620 var locModeA = this.modeA, locParticleModeA = particle.modeA; 1621 var s = locModeA.speed + locModeA.speedVar * locRandomMinus11(); 1622 1623 // direction 1624 locParticleModeA.dir.x = Math.cos(a); 1625 locParticleModeA.dir.y = Math.sin(a); 1626 cc.pMultIn(locParticleModeA.dir, s); 1627 1628 // radial accel 1629 locParticleModeA.radialAccel = locModeA.radialAccel + locModeA.radialAccelVar * locRandomMinus11(); 1630 1631 // tangential accel 1632 locParticleModeA.tangentialAccel = locModeA.tangentialAccel + locModeA.tangentialAccelVar * locRandomMinus11(); 1633 1634 // rotation is dir 1635 if(locModeA.rotationIsDir) 1636 particle.rotation = -cc.radiansToDegrees(cc.pToAngle(locParticleModeA.dir)); 1637 } else { 1638 // Mode Radius: B 1639 var locModeB = this.modeB, locParitlceModeB = particle.modeB; 1640 1641 // Set the default diameter of the particle from the source position 1642 var startRadius = locModeB.startRadius + locModeB.startRadiusVar * locRandomMinus11(); 1643 var endRadius = locModeB.endRadius + locModeB.endRadiusVar * locRandomMinus11(); 1644 1645 locParitlceModeB.radius = startRadius; 1646 locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.ParticleSystem.START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive; 1647 1648 locParitlceModeB.angle = a; 1649 locParitlceModeB.degreesPerSecond = cc.degreesToRadians(locModeB.rotatePerSecond + locModeB.rotatePerSecondVar * locRandomMinus11()); 1650 } 1651 }, 1652 1653 /** 1654 * stop emitting particles. Running particles will continue to run until they die 1655 */ 1656 stopSystem:function () { 1657 this._isActive = false; 1658 this._elapsed = this.duration; 1659 this._emitCounter = 0; 1660 }, 1661 1662 /** 1663 * Kill all living particles. 1664 */ 1665 resetSystem:function () { 1666 this._isActive = true; 1667 this._elapsed = 0; 1668 var locParticles = this._particles; 1669 for (this._particleIdx = 0; this._particleIdx < this.particleCount; ++this._particleIdx) 1670 locParticles[this._particleIdx].timeToLive = 0 ; 1671 }, 1672 1673 /** 1674 * whether or not the system is full 1675 * @return {Boolean} 1676 */ 1677 isFull:function () { 1678 return (this.particleCount >= this._totalParticles); 1679 }, 1680 1681 /** 1682 * should be overridden by subclasses 1683 * @param {cc.Particle} particle 1684 * @param {cc.Point} newPosition 1685 */ 1686 updateQuadWithParticle:function (particle, newPosition) { 1687 this._renderCmd.updateQuadWithParticle(particle, newPosition); 1688 }, 1689 1690 /** 1691 * should be overridden by subclasses 1692 */ 1693 postStep:function () { 1694 this._renderCmd.postStep(); 1695 }, 1696 1697 /** 1698 * update emitter's status 1699 * @override 1700 * @param {Number} dt delta time 1701 */ 1702 update:function (dt) { 1703 if (this._isActive && this.emissionRate) { 1704 var rate = 1.0 / this.emissionRate; 1705 //issue #1201, prevent bursts of particles, due to too high emitCounter 1706 if (this.particleCount < this._totalParticles) 1707 this._emitCounter += dt; 1708 1709 while ((this.particleCount < this._totalParticles) && (this._emitCounter > rate)) { 1710 this.addParticle(); 1711 this._emitCounter -= rate; 1712 } 1713 1714 this._elapsed += dt; 1715 if (this.duration !== -1 && this.duration < this._elapsed) 1716 this.stopSystem(); 1717 } 1718 this._particleIdx = 0; 1719 1720 var currentPosition = cc.Particle.TemporaryPoints[0]; 1721 if (this.positionType === cc.ParticleSystem.TYPE_FREE) { 1722 cc.pIn(currentPosition, this.convertToWorldSpace(this._pointZeroForParticle)); 1723 } else if (this.positionType === cc.ParticleSystem.TYPE_RELATIVE) { 1724 currentPosition.x = this._position.x; 1725 currentPosition.y = this._position.y; 1726 } 1727 1728 if (this._visible) { 1729 // Used to reduce memory allocation / creation within the loop 1730 var tpa = cc.Particle.TemporaryPoints[1], 1731 tpb = cc.Particle.TemporaryPoints[2], 1732 tpc = cc.Particle.TemporaryPoints[3]; 1733 1734 var locParticles = this._particles; 1735 while (this._particleIdx < this.particleCount) { 1736 1737 // Reset the working particles 1738 cc.pZeroIn(tpa); 1739 cc.pZeroIn(tpb); 1740 cc.pZeroIn(tpc); 1741 1742 var selParticle = locParticles[this._particleIdx]; 1743 1744 // life 1745 selParticle.timeToLive -= dt; 1746 1747 if (selParticle.timeToLive > 0) { 1748 // Mode A: gravity, direction, tangential accel & radial accel 1749 if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) { 1750 1751 var tmp = tpc, radial = tpa, tangential = tpb; 1752 1753 // radial acceleration 1754 if (selParticle.pos.x || selParticle.pos.y) { 1755 cc.pIn(radial, selParticle.pos); 1756 cc.pNormalizeIn(radial); 1757 } else { 1758 cc.pZeroIn(radial); 1759 } 1760 1761 cc.pIn(tangential, radial); 1762 cc.pMultIn(radial, selParticle.modeA.radialAccel); 1763 1764 // tangential acceleration 1765 var newy = tangential.x; 1766 tangential.x = -tangential.y; 1767 tangential.y = newy; 1768 1769 cc.pMultIn(tangential, selParticle.modeA.tangentialAccel); 1770 1771 cc.pIn(tmp, radial); 1772 cc.pAddIn(tmp, tangential); 1773 cc.pAddIn(tmp, this.modeA.gravity); 1774 cc.pMultIn(tmp, dt); 1775 cc.pAddIn(selParticle.modeA.dir, tmp); 1776 1777 1778 cc.pIn(tmp, selParticle.modeA.dir); 1779 cc.pMultIn(tmp, dt); 1780 cc.pAddIn(selParticle.pos, tmp); 1781 } else { 1782 // Mode B: radius movement 1783 var selModeB = selParticle.modeB; 1784 // Update the angle and radius of the particle. 1785 selModeB.angle += selModeB.degreesPerSecond * dt; 1786 selModeB.radius += selModeB.deltaRadius * dt; 1787 1788 selParticle.pos.x = -Math.cos(selModeB.angle) * selModeB.radius; 1789 selParticle.pos.y = -Math.sin(selModeB.angle) * selModeB.radius; 1790 } 1791 1792 // color 1793 this._renderCmd._updateDeltaColor(selParticle, dt); 1794 1795 // size 1796 selParticle.size += (selParticle.deltaSize * dt); 1797 selParticle.size = Math.max(0, selParticle.size); 1798 1799 // angle 1800 selParticle.rotation += (selParticle.deltaRotation * dt); 1801 1802 // 1803 // update values in quad 1804 // 1805 var newPos = tpa; 1806 if (this.positionType === cc.ParticleSystem.TYPE_FREE || this.positionType === cc.ParticleSystem.TYPE_RELATIVE) { 1807 var diff = tpb; 1808 cc.pIn(diff, currentPosition); 1809 cc.pSubIn(diff, selParticle.startPos); 1810 1811 cc.pIn(newPos, selParticle.pos); 1812 cc.pSubIn(newPos, diff); 1813 } else { 1814 cc.pIn(newPos, selParticle.pos); 1815 } 1816 1817 // translate newPos to correct position, since matrix transform isn't performed in batchnode 1818 // don't update the particle with the new position information, it will interfere with the radius and tangential calculations 1819 if (this._batchNode) { 1820 newPos.x += this._position.x; 1821 newPos.y += this._position.y; 1822 } 1823 this._renderCmd.updateParticlePosition(selParticle, newPos); 1824 1825 // update particle counter 1826 ++this._particleIdx; 1827 } else { 1828 // life < 0 1829 var currentIndex = selParticle.atlasIndex; 1830 if(this._particleIdx !== this.particleCount -1){ 1831 var deadParticle = locParticles[this._particleIdx]; 1832 locParticles[this._particleIdx] = locParticles[this.particleCount -1]; 1833 locParticles[this.particleCount -1] = deadParticle; 1834 } 1835 if (this._batchNode) { 1836 //disable the switched particle 1837 this._batchNode.disableParticle(this.atlasIndex + currentIndex); 1838 //switch indexes 1839 locParticles[this.particleCount - 1].atlasIndex = currentIndex; 1840 } 1841 1842 --this.particleCount; 1843 if (this.particleCount === 0 && this.autoRemoveOnFinish) { 1844 this.unscheduleUpdate(); 1845 this._parent.removeChild(this, true); 1846 return; 1847 } 1848 } 1849 } 1850 this._transformSystemDirty = false; 1851 } 1852 1853 if (!this._batchNode) 1854 this.postStep(); 1855 }, 1856 1857 /** 1858 * update emitter's status (dt = 0) 1859 */ 1860 updateWithNoTime:function () { 1861 this.update(0); 1862 }, 1863 1864 // 1865 // return the string found by key in dict. 1866 // @param {string} key 1867 // @param {object} dict 1868 // @return {String} "" if not found; return the string if found. 1869 // @private 1870 // 1871 _valueForKey:function (key, dict) { 1872 if (dict) { 1873 var pString = dict[key]; 1874 return pString != null ? pString : ""; 1875 } 1876 return ""; 1877 }, 1878 1879 _updateBlendFunc:function () { 1880 if(this._batchNode){ 1881 cc.log("Can't change blending functions when the particle is being batched"); 1882 return; 1883 } 1884 1885 var locTexture = this._texture; 1886 if (locTexture && locTexture instanceof cc.Texture2D) { 1887 this._opacityModifyRGB = false; 1888 var locBlendFunc = this._blendFunc; 1889 if (locBlendFunc.src === cc.BLEND_SRC && locBlendFunc.dst === cc.BLEND_DST) { 1890 if (locTexture.hasPremultipliedAlpha()) { 1891 this._opacityModifyRGB = true; 1892 } else { 1893 locBlendFunc.src = cc.SRC_ALPHA; 1894 locBlendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; 1895 } 1896 } 1897 } 1898 }, 1899 1900 /** 1901 * to copy object with deep copy. 1902 * returns a clone of action. 1903 * 1904 * @return {cc.ParticleSystem} 1905 */ 1906 clone:function () { 1907 var retParticle = new cc.ParticleSystem(); 1908 1909 // self, not super 1910 if (retParticle.initWithTotalParticles(this.getTotalParticles())) { 1911 // angle 1912 retParticle.setAngle(this.getAngle()); 1913 retParticle.setAngleVar(this.getAngleVar()); 1914 1915 // duration 1916 retParticle.setDuration(this.getDuration()); 1917 1918 // blend function 1919 var blend = this.getBlendFunc(); 1920 retParticle.setBlendFunc(blend.src,blend.dst); 1921 1922 // color 1923 retParticle.setStartColor(this.getStartColor()); 1924 1925 retParticle.setStartColorVar(this.getStartColorVar()); 1926 1927 retParticle.setEndColor(this.getEndColor()); 1928 1929 retParticle.setEndColorVar(this.getEndColorVar()); 1930 1931 // this size 1932 retParticle.setStartSize(this.getStartSize()); 1933 retParticle.setStartSizeVar(this.getStartSizeVar()); 1934 retParticle.setEndSize(this.getEndSize()); 1935 retParticle.setEndSizeVar(this.getEndSizeVar()); 1936 1937 // position 1938 retParticle.setPosition(cc.p(this.x, this.y)); 1939 retParticle.setPosVar(cc.p(this.getPosVar().x,this.getPosVar().y)); 1940 1941 retParticle.setPositionType(this.getPositionType()); 1942 1943 // Spinning 1944 retParticle.setStartSpin(this.getStartSpin()||0); 1945 retParticle.setStartSpinVar(this.getStartSpinVar()||0); 1946 retParticle.setEndSpin(this.getEndSpin()||0); 1947 retParticle.setEndSpinVar(this.getEndSpinVar()||0); 1948 1949 retParticle.setEmitterMode(this.getEmitterMode()); 1950 1951 // Mode A: Gravity + tangential accel + radial accel 1952 if (this.getEmitterMode() === cc.ParticleSystem.MODE_GRAVITY) { 1953 // gravity 1954 var gra = this.getGravity(); 1955 retParticle.setGravity(cc.p(gra.x,gra.y)); 1956 1957 // speed 1958 retParticle.setSpeed(this.getSpeed()); 1959 retParticle.setSpeedVar(this.getSpeedVar()); 1960 1961 // radial acceleration 1962 retParticle.setRadialAccel(this.getRadialAccel()); 1963 retParticle.setRadialAccelVar(this.getRadialAccelVar()); 1964 1965 // tangential acceleration 1966 retParticle.setTangentialAccel(this.getTangentialAccel()); 1967 retParticle.setTangentialAccelVar(this.getTangentialAccelVar()); 1968 1969 } else if (this.getEmitterMode() === cc.ParticleSystem.MODE_RADIUS) { 1970 // or Mode B: radius movement 1971 retParticle.setStartRadius(this.getStartRadius()); 1972 retParticle.setStartRadiusVar(this.getStartRadiusVar()); 1973 retParticle.setEndRadius(this.getEndRadius()); 1974 retParticle.setEndRadiusVar(this.getEndRadiusVar()); 1975 1976 retParticle.setRotatePerSecond(this.getRotatePerSecond()); 1977 retParticle.setRotatePerSecondVar(this.getRotatePerSecondVar()); 1978 } 1979 1980 // life span 1981 retParticle.setLife(this.getLife()); 1982 retParticle.setLifeVar(this.getLifeVar()); 1983 1984 // emission Rate 1985 retParticle.setEmissionRate(this.getEmissionRate()); 1986 1987 //don't get the internal texture if a batchNode is used 1988 if (!this.getBatchNode()) { 1989 // Set a compatible default for the alpha transfer 1990 retParticle.setOpacityModifyRGB(this.isOpacityModifyRGB()); 1991 // texture 1992 var texture = this.getTexture(); 1993 if(texture){ 1994 var size = texture.getContentSize(); 1995 retParticle.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height)); 1996 } 1997 } 1998 } 1999 return retParticle; 2000 }, 2001 2002 /** 2003 * <p> Sets a new CCSpriteFrame as particle.</br> 2004 * WARNING: this method is experimental. Use setTextureWithRect instead. 2005 * </p> 2006 * @param {cc.SpriteFrame} spriteFrame 2007 */ 2008 setDisplayFrame: function (spriteFrame) { 2009 if (!spriteFrame) 2010 return; 2011 2012 var locOffset = spriteFrame.getOffsetInPixels(); 2013 if (locOffset.x !== 0 || locOffset.y !== 0) 2014 cc.log("cc.ParticleSystem.setDisplayFrame(): QuadParticle only supports SpriteFrames with no offsets"); 2015 2016 // update texture before updating texture rect 2017 var texture = spriteFrame.getTexture(), locTexture = this._texture; 2018 if (locTexture !== texture) 2019 this.setTexture(texture); 2020 }, 2021 2022 /** 2023 * Sets a new texture with a rect. The rect is in Points. 2024 * @param {cc.Texture2D} texture 2025 * @param {cc.Rect} rect 2026 */ 2027 setTextureWithRect: function (texture, rect) { 2028 var locTexture = this._texture; 2029 if (locTexture !== texture) { 2030 this._texture = texture; 2031 this._updateBlendFunc(); 2032 } 2033 this.initTexCoordsWithRect(rect); 2034 }, 2035 2036 /** 2037 * listen the event that coming to foreground on Android (An empty function for native) 2038 * @param {cc.Class} obj 2039 */ 2040 listenBackToForeground:function (obj) { 2041 //do nothing 2042 } 2043 }); 2044 2045 var _p = cc.ParticleSystem.prototype; 2046 2047 // Extended properties 2048 /** @expose */ 2049 _p.opacityModifyRGB; 2050 cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB, _p.setOpacityModifyRGB); 2051 /** @expose */ 2052 _p.batchNode; 2053 cc.defineGetterSetter(_p, "batchNode", _p.getBatchNode, _p.setBatchNode); 2054 /** @expose */ 2055 _p.drawMode; 2056 cc.defineGetterSetter(_p, "drawMode", _p.getDrawMode, _p.setDrawMode); 2057 /** @expose */ 2058 _p.shapeType; 2059 cc.defineGetterSetter(_p, "shapeType", _p.getShapeType, _p.setShapeType); 2060 /** @expose */ 2061 _p.active; 2062 cc.defineGetterSetter(_p, "active", _p.isActive); 2063 /** @expose */ 2064 _p.sourcePos; 2065 cc.defineGetterSetter(_p, "sourcePos", _p.getSourcePosition, _p.setSourcePosition); 2066 /** @expose */ 2067 _p.posVar; 2068 cc.defineGetterSetter(_p, "posVar", _p.getPosVar, _p.setPosVar); 2069 /** @expose */ 2070 _p.gravity; 2071 cc.defineGetterSetter(_p, "gravity", _p.getGravity, _p.setGravity); 2072 /** @expose */ 2073 _p.speed; 2074 cc.defineGetterSetter(_p, "speed", _p.getSpeed, _p.setSpeed); 2075 /** @expose */ 2076 _p.speedVar; 2077 cc.defineGetterSetter(_p, "speedVar", _p.getSpeedVar, _p.setSpeedVar); 2078 /** @expose */ 2079 _p.tangentialAccel; 2080 cc.defineGetterSetter(_p, "tangentialAccel", _p.getTangentialAccel, _p.setTangentialAccel); 2081 /** @expose */ 2082 _p.tangentialAccelVar; 2083 cc.defineGetterSetter(_p, "tangentialAccelVar", _p.getTangentialAccelVar, _p.setTangentialAccelVar); 2084 /** @expose */ 2085 _p.radialAccel; 2086 cc.defineGetterSetter(_p, "radialAccel", _p.getRadialAccel, _p.setRadialAccel); 2087 /** @expose */ 2088 _p.radialAccelVar; 2089 cc.defineGetterSetter(_p, "radialAccelVar", _p.getRadialAccelVar, _p.setRadialAccelVar); 2090 /** @expose */ 2091 _p.rotationIsDir; 2092 cc.defineGetterSetter(_p, "rotationIsDir", _p.getRotationIsDir, _p.setRotationIsDir); 2093 /** @expose */ 2094 _p.startRadius; 2095 cc.defineGetterSetter(_p, "startRadius", _p.getStartRadius, _p.setStartRadius); 2096 /** @expose */ 2097 _p.startRadiusVar; 2098 cc.defineGetterSetter(_p, "startRadiusVar", _p.getStartRadiusVar, _p.setStartRadiusVar); 2099 /** @expose */ 2100 _p.endRadius; 2101 cc.defineGetterSetter(_p, "endRadius", _p.getEndRadius, _p.setEndRadius); 2102 /** @expose */ 2103 _p.endRadiusVar; 2104 cc.defineGetterSetter(_p, "endRadiusVar", _p.getEndRadiusVar, _p.setEndRadiusVar); 2105 /** @expose */ 2106 _p.rotatePerS; 2107 cc.defineGetterSetter(_p, "rotatePerS", _p.getRotatePerSecond, _p.setRotatePerSecond); 2108 /** @expose */ 2109 _p.rotatePerSVar; 2110 cc.defineGetterSetter(_p, "rotatePerSVar", _p.getRotatePerSecondVar, _p.setRotatePerSecondVar); 2111 /** @expose */ 2112 _p.startColor; 2113 cc.defineGetterSetter(_p, "startColor", _p.getStartColor, _p.setStartColor); 2114 /** @expose */ 2115 _p.startColorVar; 2116 cc.defineGetterSetter(_p, "startColorVar", _p.getStartColorVar, _p.setStartColorVar); 2117 /** @expose */ 2118 _p.endColor; 2119 cc.defineGetterSetter(_p, "endColor", _p.getEndColor, _p.setEndColor); 2120 /** @expose */ 2121 _p.endColorVar; 2122 cc.defineGetterSetter(_p, "endColorVar", _p.getEndColorVar, _p.setEndColorVar); 2123 /** @expose */ 2124 _p.totalParticles; 2125 cc.defineGetterSetter(_p, "totalParticles", _p.getTotalParticles, _p.setTotalParticles); 2126 /** @expose */ 2127 _p.texture; 2128 cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture); 2129 2130 2131 /** 2132 * <p> return the string found by key in dict. <br/> 2133 * This plist files can be create manually or with Particle Designer:<br/> 2134 * http://particledesigner.71squared.com/<br/> 2135 * </p> 2136 * @deprecated since v3.0 please use new cc.ParticleSysytem(plistFile) instead. 2137 * @param {String|Number} plistFile 2138 * @return {cc.ParticleSystem} 2139 */ 2140 cc.ParticleSystem.create = function (plistFile) { 2141 return new cc.ParticleSystem(plistFile); 2142 }; 2143 2144 /** 2145 * <p> return the string found by key in dict. <br/> 2146 * This plist files can be create manually or with Particle Designer:<br/> 2147 * http://particledesigner.71squared.com/<br/> 2148 * </p> 2149 * @deprecated since v3.0 please use new cc.ParticleSysytem(plistFile) instead. 2150 * @function 2151 * @param {String|Number} plistFile 2152 * @return {cc.ParticleSystem} 2153 */ 2154 cc.ParticleSystem.createWithTotalParticles = cc.ParticleSystem.create; 2155 2156 // Different modes 2157 /** 2158 * Mode A:Gravity + Tangential Accel + Radial Accel 2159 * @Class 2160 * @Construct 2161 * @param {cc.Point} [gravity=] Gravity value. 2162 * @param {Number} [speed=0] speed of each particle. 2163 * @param {Number} [speedVar=0] speed variance of each particle. 2164 * @param {Number} [tangentialAccel=0] tangential acceleration of each particle. 2165 * @param {Number} [tangentialAccelVar=0] tangential acceleration variance of each particle. 2166 * @param {Number} [radialAccel=0] radial acceleration of each particle. 2167 * @param {Number} [radialAccelVar=0] radial acceleration variance of each particle. 2168 * @param {boolean} [rotationIsDir=false] 2169 */ 2170 cc.ParticleSystem.ModeA = function (gravity, speed, speedVar, tangentialAccel, tangentialAccelVar, radialAccel, radialAccelVar, rotationIsDir) { 2171 /** Gravity value. Only available in 'Gravity' mode. */ 2172 this.gravity = gravity ? gravity : cc.p(0,0); 2173 /** speed of each particle. Only available in 'Gravity' mode. */ 2174 this.speed = speed || 0; 2175 /** speed variance of each particle. Only available in 'Gravity' mode. */ 2176 this.speedVar = speedVar || 0; 2177 /** tangential acceleration of each particle. Only available in 'Gravity' mode. */ 2178 this.tangentialAccel = tangentialAccel || 0; 2179 /** tangential acceleration variance of each particle. Only available in 'Gravity' mode. */ 2180 this.tangentialAccelVar = tangentialAccelVar || 0; 2181 /** radial acceleration of each particle. Only available in 'Gravity' mode. */ 2182 this.radialAccel = radialAccel || 0; 2183 /** radial acceleration variance of each particle. Only available in 'Gravity' mode. */ 2184 this.radialAccelVar = radialAccelVar || 0; 2185 /** set the rotation of each particle to its direction Only available in 'Gravity' mode. */ 2186 this.rotationIsDir = rotationIsDir || false; 2187 }; 2188 2189 /** 2190 * Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) 2191 * @Class 2192 * @Construct 2193 * @param {Number} [startRadius=0] The starting radius of the particles. 2194 * @param {Number} [startRadiusVar=0] The starting radius variance of the particles. 2195 * @param {Number} [endRadius=0] The ending radius of the particles. 2196 * @param {Number} [endRadiusVar=0] The ending radius variance of the particles. 2197 * @param {Number} [rotatePerSecond=0] Number of degrees to rotate a particle around the source pos per second. 2198 * @param {Number} [rotatePerSecondVar=0] Variance in degrees for rotatePerSecond. 2199 */ 2200 cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endRadiusVar, rotatePerSecond, rotatePerSecondVar) { 2201 /** The starting radius of the particles. Only available in 'Radius' mode. */ 2202 this.startRadius = startRadius || 0; 2203 /** The starting radius variance of the particles. Only available in 'Radius' mode. */ 2204 this.startRadiusVar = startRadiusVar || 0; 2205 /** The ending radius of the particles. Only available in 'Radius' mode. */ 2206 this.endRadius = endRadius || 0; 2207 /** The ending radius variance of the particles. Only available in 'Radius' mode. */ 2208 this.endRadiusVar = endRadiusVar || 0; 2209 /** Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. */ 2210 this.rotatePerSecond = rotatePerSecond || 0; 2211 /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */ 2212 this.rotatePerSecondVar = rotatePerSecondVar || 0; 2213 }; 2214 2215 /** 2216 * Shape Mode of Particle Draw 2217 * @constant 2218 * @type Number 2219 */ 2220 cc.ParticleSystem.SHAPE_MODE = 0; 2221 2222 /** 2223 * Texture Mode of Particle Draw 2224 * @constant 2225 * @type Number 2226 */ 2227 cc.ParticleSystem.TEXTURE_MODE = 1; 2228 2229 /** 2230 * Star Shape for ShapeMode of Particle 2231 * @constant 2232 * @type Number 2233 */ 2234 cc.ParticleSystem.STAR_SHAPE = 0; 2235 2236 /** 2237 * Ball Shape for ShapeMode of Particle 2238 * @constant 2239 * @type Number 2240 */ 2241 cc.ParticleSystem.BALL_SHAPE = 1; 2242 2243 /** 2244 * The Particle emitter lives forever 2245 * @constant 2246 * @type Number 2247 */ 2248 cc.ParticleSystem.DURATION_INFINITY = -1; 2249 2250 /** 2251 * The starting size of the particle is equal to the ending size 2252 * @constant 2253 * @type Number 2254 */ 2255 cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE = -1; 2256 2257 /** 2258 * The starting radius of the particle is equal to the ending radius 2259 * @constant 2260 * @type Number 2261 */ 2262 cc.ParticleSystem.START_RADIUS_EQUAL_TO_END_RADIUS = -1; 2263 2264 /** 2265 * Gravity mode (A mode) 2266 * @constant 2267 * @type Number 2268 */ 2269 cc.ParticleSystem.MODE_GRAVITY = 0; 2270 2271 /** 2272 * Radius mode (B mode) 2273 * @constant 2274 * @type Number 2275 */ 2276 cc.ParticleSystem.MODE_RADIUS = 1; 2277 2278 /** 2279 * Living particles are attached to the world and are unaffected by emitter repositioning. 2280 * @constant 2281 * @type Number 2282 */ 2283 cc.ParticleSystem.TYPE_FREE = 0; 2284 2285 /** 2286 * Living particles are attached to the world but will follow the emitter repositioning.<br/> 2287 * Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite. 2288 * @constant 2289 * @type Number 2290 */ 2291 cc.ParticleSystem.TYPE_RELATIVE = 1; 2292 2293 /** 2294 * Living particles are attached to the emitter and are translated along with it. 2295 * @constant 2296 * @type Number 2297 */ 2298 cc.ParticleSystem.TYPE_GROUPED = 2; 2299