1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 // 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 * Shape Mode of Particle Draw 46 * @constant 47 * @type Number 48 */ 49 cc.PARTICLE_SHAPE_MODE = 0; 50 /** 51 * Texture Mode of Particle Draw 52 * @constant 53 * @type Number 54 */ 55 cc.PARTICLE_TEXTURE_MODE = 1; 56 57 /** 58 * Star Shape for ShapeMode of Particle 59 * @constant 60 * @type Number 61 */ 62 cc.PARTICLE_STAR_SHAPE = 0; 63 /** 64 * Ball Shape for ShapeMode of Particle 65 * @constant 66 * @type Number 67 */ 68 cc.PARTICLE_BALL_SHAPE = 1; 69 70 /** 71 * The Particle emitter lives forever 72 * @constant 73 * @type Number 74 */ 75 cc.PARTICLE_DURATION_INFINITY = -1; 76 77 /** 78 * The starting size of the particle is equal to the ending size 79 * @constant 80 * @type Number 81 */ 82 cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE = -1; 83 84 /** 85 * The starting radius of the particle is equal to the ending radius 86 * @constant 87 * @type Number 88 */ 89 cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS = -1; 90 91 /** 92 * Gravity mode (A mode) 93 * @constant 94 * @type Number 95 */ 96 cc.PARTICLE_MODE_GRAVITY = 0; 97 98 /** 99 * Radius mode (B mode) 100 * @constant 101 * @type Number 102 */ 103 cc.PARTICLE_MODE_RADIUS = 1; 104 105 // tCCPositionType 106 // possible types of particle positions 107 108 /** 109 * Living particles are attached to the world and are unaffected by emitter repositioning. 110 * @constant 111 * @type Number 112 */ 113 cc.PARTICLE_TYPE_FREE = 0; 114 115 /** 116 * Living particles are attached to the world but will follow the emitter repositioning.<br/> 117 * Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite. 118 * @constant 119 * @type Number 120 */ 121 cc.PARTICLE_TYPE_RELATIVE = 1; 122 123 /** 124 * Living particles are attached to the emitter and are translated along with it. 125 * @constant 126 * @type Number 127 */ 128 cc.PARTICLE_TYPE_GROUPED = 2; 129 130 /** 131 * Structure that contains the values of each particle 132 * @Class 133 * @Construct 134 * @param {cc.Point} [pos=cc.PointZero()] Position of particle 135 * @param {cc.Point} [startPos=cc.PointZero()] 136 * @param {cc.Color4F} [color= cc.Color4F(0, 0, 0, 1)] 137 * @param {cc.Color4F} [deltaColor=cc.Color4F(0, 0, 0, 1)] 138 * @param {cc.Size} [size=0] 139 * @param {cc.Size} [deltaSize=0] 140 * @param {Number} [rotation=0] 141 * @param {Number} [deltaRotation=0] 142 * @param {Number} [timeToLive=0] 143 * @param {Number} [atlasIndex=0] 144 * @param {cc.Particle.ModeA} [modeA=] 145 * @param {cc.Particle.ModeA} [modeB=] 146 */ 147 cc.Particle = function (pos, startPos, color, deltaColor, size, deltaSize, rotation, deltaRotation, timeToLive, atlasIndex, modeA, modeB) { 148 this.pos = pos ? pos : cc.PointZero(); 149 this.startPos = startPos ? startPos : cc.PointZero(); 150 this.color = color ? color : new cc.Color4F(0, 0, 0, 1); 151 this.deltaColor = deltaColor ? deltaColor : new cc.Color4F(0, 0, 0, 1); 152 this.size = size || 0; 153 this.deltaSize = deltaSize || 0; 154 this.rotation = rotation || 0; 155 this.deltaRotation = deltaRotation || 0; 156 this.timeToLive = timeToLive || 0; 157 this.atlasIndex = atlasIndex || 0; 158 this.modeA = modeA ? modeA : new cc.Particle.ModeA(); 159 this.modeB = modeB ? modeB : new cc.Particle.ModeB(); 160 this.isChangeColor = false; 161 this.drawPos = cc.p(0, 0); 162 }; 163 164 /** 165 * Mode A: gravity, direction, radial accel, tangential accel 166 * @Class 167 * @Construct 168 * @param {cc.Point} dir direction of particle 169 * @param {Number} radialAccel 170 * @param {Number} tangentialAccel 171 */ 172 cc.Particle.ModeA = function (dir, radialAccel, tangentialAccel) { 173 this.dir = dir ? dir : cc.PointZero(); 174 this.radialAccel = radialAccel || 0; 175 this.tangentialAccel = tangentialAccel || 0; 176 }; 177 178 /** 179 * Mode B: radius mode 180 * @Class 181 * @Construct 182 * @param {Number} angle 183 * @param {Number} degreesPerSecond 184 * @param {Number} radius 185 * @param {Number} deltaRadius 186 */ 187 cc.Particle.ModeB = function (angle, degreesPerSecond, radius, deltaRadius) { 188 this.angle = angle || 0; 189 this.degreesPerSecond = degreesPerSecond || 0; 190 this.radius = radius || 0; 191 this.deltaRadius = deltaRadius || 0; 192 }; 193 194 /** 195 * Array of Point instances used to optimize particle updates 196 */ 197 cc.Particle.TemporaryPoints = [ 198 cc.p(), 199 cc.p(), 200 cc.p(), 201 cc.p() 202 ]; 203 204 /** 205 * <p> 206 * Particle System base class. <br/> 207 * Attributes of a Particle System:<br/> 208 * - emmision rate of the particles<br/> 209 * - Gravity Mode (Mode A): <br/> 210 * - gravity <br/> 211 * - direction <br/> 212 * - speed +- variance <br/> 213 * - tangential acceleration +- variance<br/> 214 * - radial acceleration +- variance<br/> 215 * - Radius Mode (Mode B): <br/> 216 * - startRadius +- variance <br/> 217 * - endRadius +- variance <br/> 218 * - rotate +- variance <br/> 219 * - Properties common to all modes: <br/> 220 * - life +- life variance <br/> 221 * - start spin +- variance <br/> 222 * - end spin +- variance <br/> 223 * - start size +- variance <br/> 224 * - end size +- variance <br/> 225 * - start color +- variance <br/> 226 * - end color +- variance <br/> 227 * - life +- variance <br/> 228 * - blending function <br/> 229 * - texture <br/> 230 * <br/> 231 * cocos2d also supports particles generated by Particle Designer (http://particledesigner.71squared.com/).<br/> 232 * 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d, <br/> 233 * cocos2d uses a another approach, but the results are almost identical.<br/> 234 * cocos2d supports all the variables used by Particle Designer plus a bit more: <br/> 235 * - spinning particles (supported when using ParticleSystem) <br/> 236 * - tangential acceleration (Gravity mode) <br/> 237 * - radial acceleration (Gravity mode) <br/> 238 * - radius direction (Radius mode) (Particle Designer supports outwards to inwards direction only) <br/> 239 * It is possible to customize any of the above mentioned properties in runtime. Example: <br/> 240 * </p> 241 * @class 242 * @extends cc.Node 243 * 244 * @example 245 * emitter.radialAccel = 15; 246 * emitter.startSpin = 0; 247 */ 248 cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ 249 //***********variables************* 250 _plistFile: "", 251 //! time elapsed since the start of the system (in seconds) 252 _elapsed: 0, 253 254 _dontTint: false, 255 256 // Different modes 257 //! Mode A:Gravity + Tangential Accel + Radial Accel 258 modeA: null, 259 //! Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) 260 modeB: null, 261 262 //private POINTZERO for ParticleSystem 263 _pointZeroForParticle: cc.p(0, 0), 264 265 //! Array of particles 266 _particles: null, 267 268 // color modulate 269 // BOOL colorModulate; 270 271 //! How many particles can be emitted per second 272 _emitCounter: 0, 273 //! particle idx 274 _particleIdx: 0, 275 276 _batchNode: null, 277 _atlasIndex: 0, 278 279 //true if scaled or rotated 280 _transformSystemDirty: false, 281 _allocatedParticles: 0, 282 283 //drawMode 284 _drawMode: cc.PARTICLE_SHAPE_MODE, 285 286 //shape type 287 _shapeType: cc.PARTICLE_BALL_SHAPE, 288 _isActive: false, 289 _particleCount: 0, 290 _duration: 0, 291 _sourcePosition: null, 292 _posVar: null, 293 _life: 0, 294 _lifeVar: 0, 295 _angle: 0, 296 _angleVar: 0, 297 _startSize: 0, 298 _startSizeVar: 0, 299 _endSize: 0, 300 _endSizeVar: 0, 301 _startColor: null, 302 _startColorVar: null, 303 _endColor: null, 304 _endColorVar: null, 305 _startSpin: 0, 306 _startSpinVar: 0, 307 _endSpin: 0, 308 _endSpinVar: 0, 309 _emissionRate: 0, 310 _totalParticles: 0, 311 _texture: null, 312 _blendFunc: null, 313 _opacityModifyRGB: false, 314 _positionType: cc.PARTICLE_TYPE_FREE, 315 _isAutoRemoveOnFinish: false, 316 _emitterMode: 0, 317 318 // quads to be rendered 319 _quads:null, 320 // indices 321 _indices:null, 322 323 //_VAOname:0, 324 //0: vertex 1: indices 325 _buffersVBO:null, 326 _pointRect:null, 327 328 _textureLoaded: null, 329 _quadsArrayBuffer:null, 330 331 /** 332 * Constructor 333 * @override 334 */ 335 ctor:function () { 336 cc.Node.prototype.ctor.call(this); 337 this._emitterMode = cc.PARTICLE_MODE_GRAVITY; 338 this.modeA = new cc.ParticleSystem.ModeA(); 339 this.modeB = new cc.ParticleSystem.ModeB(); 340 this._blendFunc = {src:cc.BLEND_SRC, dst:cc.BLEND_DST}; 341 342 this._particles = []; 343 this._sourcePosition = new cc.Point(0, 0); 344 this._posVar = new cc.Point(0, 0); 345 346 this._startColor = new cc.Color4F(1, 1, 1, 1); 347 this._startColorVar = new cc.Color4F(1, 1, 1, 1); 348 this._endColor = new cc.Color4F(1, 1, 1, 1); 349 this._endColorVar = new cc.Color4F(1, 1, 1, 1); 350 351 this._plistFile = ""; 352 this._elapsed = 0; 353 this._dontTint = false; 354 this._pointZeroForParticle = cc.p(0, 0); 355 this._emitCounter = 0; 356 this._particleIdx = 0; 357 this._batchNode = null; 358 this._atlasIndex = 0; 359 360 this._transformSystemDirty = false; 361 this._allocatedParticles = 0; 362 this._drawMode = cc.PARTICLE_SHAPE_MODE; 363 this._shapeType = cc.PARTICLE_BALL_SHAPE; 364 this._isActive = false; 365 this._particleCount = 0; 366 this._duration = 0; 367 this._life = 0; 368 this._lifeVar = 0; 369 this._angle = 0; 370 this._angleVar = 0; 371 this._startSize = 0; 372 this._startSizeVar = 0; 373 this._endSize = 0; 374 this._endSizeVar = 0; 375 376 this._startSpin = 0; 377 this._startSpinVar = 0; 378 this._endSpin = 0; 379 this._endSpinVar = 0; 380 this._emissionRate = 0; 381 this._totalParticles = 0; 382 this._texture = null; 383 this._opacityModifyRGB = false; 384 this._positionType = cc.PARTICLE_TYPE_FREE; 385 this._isAutoRemoveOnFinish = false; 386 387 this._buffersVBO = [0, 0]; 388 this._quads = []; 389 this._indices = []; 390 this._pointRect = cc.RectZero(); 391 this._textureLoaded = true; 392 393 if (cc.renderContextType === cc.WEBGL) { 394 this._quadsArrayBuffer = null; 395 } 396 }, 397 398 /** 399 * initializes the indices for the vertices 400 */ 401 initIndices:function () { 402 var locIndices = this._indices; 403 for (var i = 0, len = this._totalParticles; i < len; ++i) { 404 var i6 = i * 6; 405 var i4 = i * 4; 406 locIndices[i6 + 0] = i4 + 0; 407 locIndices[i6 + 1] = i4 + 1; 408 locIndices[i6 + 2] = i4 + 2; 409 410 locIndices[i6 + 5] = i4 + 1; 411 locIndices[i6 + 4] = i4 + 2; 412 locIndices[i6 + 3] = i4 + 3; 413 } 414 }, 415 416 /** 417 * <p> initializes the texture with a rectangle measured Points<br/> 418 * pointRect should be in Texture coordinates, not pixel coordinates 419 * </p> 420 * @param {cc.Rect} pointRect 421 */ 422 initTexCoordsWithRect:function (pointRect) { 423 var scaleFactor = cc.CONTENT_SCALE_FACTOR(); 424 // convert to pixels coords 425 var rect = cc.rect( 426 pointRect.x * scaleFactor, 427 pointRect.y * scaleFactor, 428 pointRect.width * scaleFactor, 429 pointRect.height * scaleFactor); 430 431 var wide = pointRect.width; 432 var high = pointRect.height; 433 434 if (this._texture) { 435 wide = this._texture.getPixelsWide(); 436 high = this._texture.getPixelsHigh(); 437 } 438 439 if(cc.renderContextType === cc.CANVAS) 440 return; 441 442 var left, bottom, right, top; 443 if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { 444 left = (rect.x * 2 + 1) / (wide * 2); 445 bottom = (rect.y * 2 + 1) / (high * 2); 446 right = left + (rect.width * 2 - 2) / (wide * 2); 447 top = bottom + (rect.height * 2 - 2) / (high * 2); 448 } else { 449 left = rect.x / wide; 450 bottom = rect.y / high; 451 right = left + rect.width / wide; 452 top = bottom + rect.height / high; 453 } 454 455 // Important. Texture in cocos2d are inverted, so the Y component should be inverted 456 var temp = top; 457 top = bottom; 458 bottom = temp; 459 460 var quads; 461 var start = 0, end = 0; 462 if (this._batchNode) { 463 quads = this._batchNode.getTextureAtlas().getQuads(); 464 start = this._atlasIndex; 465 end = this._atlasIndex + this._totalParticles; 466 } else { 467 quads = this._quads; 468 start = 0; 469 end = this._totalParticles; 470 } 471 472 for (var i = start; i < end; i++) { 473 if (!quads[i]) 474 quads[i] = cc.V3F_C4B_T2F_QuadZero(); 475 476 // bottom-left vertex: 477 var selQuad = quads[i]; 478 selQuad.bl.texCoords.u = left; 479 selQuad.bl.texCoords.v = bottom; 480 // bottom-right vertex: 481 selQuad.br.texCoords.u = right; 482 selQuad.br.texCoords.v = bottom; 483 // top-left vertex: 484 selQuad.tl.texCoords.u = left; 485 selQuad.tl.texCoords.v = top; 486 // top-right vertex: 487 selQuad.tr.texCoords.u = right; 488 selQuad.tr.texCoords.v = top; 489 } 490 }, 491 492 /** 493 * return weak reference to the cc.SpriteBatchNode that renders the cc.Sprite 494 * @return {cc.ParticleBatchNode} 495 */ 496 getBatchNode:function () { 497 return this._batchNode; 498 }, 499 500 /** 501 * set weak reference to the cc.SpriteBatchNode that renders the cc.Sprite 502 * @param {cc.ParticleBatchNode} batchNode 503 */ 504 setBatchNode:function (batchNode) { 505 if (this._batchNode != batchNode) { 506 var oldBatch = this._batchNode; 507 508 this._batchNode = batchNode; //weak reference 509 510 if (batchNode) { 511 var locParticles = this._particles; 512 for (var i = 0; i < this._totalParticles; i++) 513 locParticles[i].atlasIndex = i; 514 } 515 516 // NEW: is self render ? 517 if (!batchNode) { 518 this._allocMemory(); 519 this.initIndices(); 520 this.setTexture(oldBatch.getTexture()); 521 //if (cc.TEXTURE_ATLAS_USE_VAO) 522 // this._setupVBOandVAO(); 523 //else 524 this._setupVBO(); 525 } else if (!oldBatch) { 526 // OLD: was it self render cleanup ? 527 // copy current state to batch 528 this._batchNode.getTextureAtlas()._copyQuadsToTextureAtlas(this._quads, this._atlasIndex); 529 530 //delete buffer 531 cc.renderContext.deleteBuffer(this._buffersVBO[1]); //where is re-bindBuffer code? 532 533 //if (cc.TEXTURE_ATLAS_USE_VAO) 534 // glDeleteVertexArrays(1, this._VAOname); 535 } 536 } 537 }, 538 539 /** 540 * return index of system in batch node array 541 * @return {Number} 542 */ 543 getAtlasIndex:function () { 544 return this._atlasIndex; 545 }, 546 547 /** 548 * set index of system in batch node array 549 * @param {Number} atlasIndex 550 */ 551 setAtlasIndex:function (atlasIndex) { 552 this._atlasIndex = atlasIndex; 553 }, 554 555 /** 556 * Return DrawMode of ParticleSystem 557 * @return {Number} 558 */ 559 getDrawMode:function () { 560 return this._drawMode; 561 }, 562 563 /** 564 * DrawMode of ParticleSystem setter 565 * @param {Number} drawMode 566 */ 567 setDrawMode:function (drawMode) { 568 this._drawMode = drawMode; 569 }, 570 571 /** 572 * Return ShapeType of ParticleSystem 573 * @return {Number} 574 */ 575 getShapeType:function () { 576 return this._shapeType; 577 }, 578 579 /** 580 * ShapeType of ParticleSystem setter 581 * @param {Number} shapeType 582 */ 583 setShapeType:function (shapeType) { 584 this._shapeType = shapeType; 585 }, 586 587 /** 588 * Return ParticleSystem is active 589 * @return {Boolean} 590 */ 591 isActive:function () { 592 return this._isActive; 593 }, 594 595 /** 596 * Quantity of particles that are being simulated at the moment 597 * @return {Number} 598 */ 599 getParticleCount:function () { 600 return this._particleCount; 601 }, 602 603 /** 604 * Quantity of particles setter 605 * @param {Number} particleCount 606 */ 607 setParticleCount:function (particleCount) { 608 this._particleCount = particleCount; 609 }, 610 611 /** 612 * How many seconds the emitter wil run. -1 means 'forever' 613 * @return {Number} 614 */ 615 getDuration:function () { 616 return this._duration; 617 }, 618 619 /** 620 * set run seconds of the emitter 621 * @param {Number} duration 622 */ 623 setDuration:function (duration) { 624 this._duration = duration; 625 }, 626 627 /** 628 * Return sourcePosition of the emitter 629 * @return {cc.Point | Object} 630 */ 631 getSourcePosition:function () { 632 return {x:this._sourcePosition.x, y:this._sourcePosition.y}; 633 }, 634 635 /** 636 * sourcePosition of the emitter setter 637 * @param sourcePosition 638 */ 639 setSourcePosition:function (sourcePosition) { 640 this._sourcePosition = sourcePosition; 641 }, 642 643 /** 644 * Return Position variance of the emitter 645 * @return {cc.Point | Object} 646 */ 647 getPosVar:function () { 648 return {x: this._posVar.x, y: this._posVar.y}; 649 }, 650 651 /** 652 * Position variance of the emitter setter 653 * @param {cc.Point} posVar 654 */ 655 setPosVar:function (posVar) { 656 this._posVar = posVar; 657 }, 658 659 /** 660 * Return life of each particle 661 * @return {Number} 662 */ 663 getLife:function () { 664 return this._life; 665 }, 666 667 /** 668 * life of each particle setter 669 * @param {Number} life 670 */ 671 setLife:function (life) { 672 this._life = life; 673 }, 674 675 /** 676 * Return life variance of each particle 677 * @return {Number} 678 */ 679 getLifeVar:function () { 680 return this._lifeVar; 681 }, 682 683 /** 684 * life variance of each particle setter 685 * @param {Number} lifeVar 686 */ 687 setLifeVar:function (lifeVar) { 688 this._lifeVar = lifeVar; 689 }, 690 691 /** 692 * Return angle of each particle 693 * @return {Number} 694 */ 695 getAngle:function () { 696 return this._angle; 697 }, 698 699 /** 700 * angle of each particle setter 701 * @param {Number} angle 702 */ 703 setAngle:function (angle) { 704 this._angle = angle; 705 }, 706 707 /** 708 * Return angle variance of each particle 709 * @return {Number} 710 */ 711 getAngleVar:function () { 712 return this._angleVar; 713 }, 714 715 /** 716 * angle variance of each particle setter 717 * @param angleVar 718 */ 719 setAngleVar:function (angleVar) { 720 this._angleVar = angleVar; 721 }, 722 723 // mode A 724 /** 725 * Return Gravity of emitter 726 * @return {cc.Point} 727 */ 728 getGravity:function () { 729 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 730 return this.modeA.gravity; 731 }, 732 733 /** 734 * Gravity of emitter setter 735 * @param {cc.Point} gravity 736 */ 737 setGravity:function (gravity) { 738 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 739 this.modeA.gravity = gravity; 740 }, 741 742 /** 743 * Return Speed of each particle 744 * @return {Number} 745 */ 746 getSpeed:function () { 747 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 748 return this.modeA.speed; 749 }, 750 751 /** 752 * Speed of each particle setter 753 * @param {Number} speed 754 */ 755 setSpeed:function (speed) { 756 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 757 this.modeA.speed = speed; 758 }, 759 760 /** 761 * return speed variance of each particle. Only available in 'Gravity' mode. 762 * @return {Number} 763 */ 764 getSpeedVar:function () { 765 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 766 return this.modeA.speedVar; 767 }, 768 769 /** 770 * speed variance of each particle setter. Only available in 'Gravity' mode. 771 * @param {Number} speedVar 772 */ 773 setSpeedVar:function (speedVar) { 774 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 775 this.modeA.speedVar = speedVar; 776 }, 777 778 /** 779 * Return tangential acceleration of each particle. Only available in 'Gravity' mode. 780 * @return {Number} 781 */ 782 getTangentialAccel:function () { 783 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 784 return this.modeA.tangentialAccel; 785 }, 786 787 /** 788 * Tangential acceleration of each particle setter. Only available in 'Gravity' mode. 789 * @param {Number} tangentialAccel 790 */ 791 setTangentialAccel:function (tangentialAccel) { 792 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 793 this.modeA.tangentialAccel = tangentialAccel; 794 }, 795 796 /** 797 * Return tangential acceleration variance of each particle. Only available in 'Gravity' mode. 798 * @return {Number} 799 */ 800 getTangentialAccelVar:function () { 801 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 802 return this.modeA.tangentialAccelVar; 803 }, 804 805 /** 806 * tangential acceleration variance of each particle setter. Only available in 'Gravity' mode. 807 * @param {Number} tangentialAccelVar 808 */ 809 setTangentialAccelVar:function (tangentialAccelVar) { 810 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 811 this.modeA.tangentialAccelVar = tangentialAccelVar; 812 }, 813 814 /** 815 * Return radial acceleration of each particle. Only available in 'Gravity' mode. 816 * @return {Number} 817 */ 818 getRadialAccel:function () { 819 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 820 return this.modeA.radialAccel; 821 }, 822 823 /** 824 * radial acceleration of each particle setter. Only available in 'Gravity' mode. 825 * @param {Number} radialAccel 826 */ 827 setRadialAccel:function (radialAccel) { 828 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 829 this.modeA.radialAccel = radialAccel; 830 }, 831 832 /** 833 * Return radial acceleration variance of each particle. Only available in 'Gravity' mode. 834 * @return {Number} 835 */ 836 getRadialAccelVar:function () { 837 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 838 return this.modeA.radialAccelVar; 839 }, 840 841 /** 842 * radial acceleration variance of each particle setter. Only available in 'Gravity' mode. 843 * @param {Number} radialAccelVar 844 */ 845 setRadialAccelVar:function (radialAccelVar) { 846 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 847 this.modeA.radialAccelVar = radialAccelVar; 848 }, 849 850 /** 851 * get the rotation of each particle to its direction Only available in 'Gravity' mode. 852 * @returns {boolean} 853 */ 854 getRotationIsDir: function(){ 855 cc.Assert( this._emitterMode === cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 856 return this.modeA.rotationIsDir; 857 }, 858 859 /** 860 * set the rotation of each particle to its direction Only available in 'Gravity' mode. 861 * @param {boolean} t 862 */ 863 setRotationIsDir: function(t){ 864 cc.Assert( this._emitterMode === cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity"); 865 this.modeA.rotationIsDir = t; 866 }, 867 868 // mode B 869 /** 870 * Return starting radius of the particles. Only available in 'Radius' mode. 871 * @return {Number} 872 */ 873 getStartRadius:function () { 874 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 875 return this.modeB.startRadius; 876 }, 877 878 /** 879 * starting radius of the particles setter. Only available in 'Radius' mode. 880 * @param {Number} startRadius 881 */ 882 setStartRadius:function (startRadius) { 883 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 884 this.modeB.startRadius = startRadius; 885 }, 886 887 /** 888 * Return starting radius variance of the particles. Only available in 'Radius' mode. 889 * @return {Number} 890 */ 891 getStartRadiusVar:function () { 892 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 893 return this.modeB.startRadiusVar; 894 }, 895 896 /** 897 * starting radius variance of the particles setter. Only available in 'Radius' mode. 898 * @param {Number} startRadiusVar 899 */ 900 setStartRadiusVar:function (startRadiusVar) { 901 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 902 this.modeB.startRadiusVar = startRadiusVar; 903 }, 904 905 /** 906 * Return ending radius of the particles. Only available in 'Radius' mode. 907 * @return {Number} 908 */ 909 getEndRadius:function () { 910 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 911 return this.modeB.endRadius; 912 }, 913 914 /** 915 * ending radius of the particles setter. Only available in 'Radius' mode. 916 * @param {Number} endRadius 917 */ 918 setEndRadius:function (endRadius) { 919 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 920 this.modeB.endRadius = endRadius; 921 }, 922 923 /** 924 * Return ending radius variance of the particles. Only available in 'Radius' mode. 925 * @return {Number} 926 */ 927 getEndRadiusVar:function () { 928 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 929 return this.modeB.endRadiusVar; 930 }, 931 932 /** 933 * ending radius variance of the particles setter. Only available in 'Radius' mode. 934 * @param endRadiusVar 935 */ 936 setEndRadiusVar:function (endRadiusVar) { 937 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 938 this.modeB.endRadiusVar = endRadiusVar; 939 }, 940 941 /** 942 * get Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. 943 * @return {Number} 944 */ 945 getRotatePerSecond:function () { 946 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 947 return this.modeB.rotatePerSecond; 948 }, 949 950 /** 951 * set Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. 952 * @param {Number} degrees 953 */ 954 setRotatePerSecond:function (degrees) { 955 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 956 this.modeB.rotatePerSecond = degrees; 957 }, 958 959 /** 960 * Return Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. 961 * @return {Number} 962 */ 963 getRotatePerSecondVar:function () { 964 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 965 return this.modeB.rotatePerSecondVar; 966 }, 967 968 /** 969 * Variance in degrees for rotatePerSecond setter. Only available in 'Radius' mode. 970 * @param degrees 971 */ 972 setRotatePerSecondVar:function (degrees) { 973 cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius"); 974 this.modeB.rotatePerSecondVar = degrees; 975 }, 976 ////////////////////////////////////////////////////////////////////////// 977 978 //don't use a transform matrix, this is faster 979 setScale:function (scale, scaleY) { 980 this._transformSystemDirty = true; 981 cc.Node.prototype.setScale.call(this, scale, scaleY); 982 }, 983 984 setRotation:function (newRotation) { 985 this._transformSystemDirty = true; 986 cc.Node.prototype.setRotation.call(this, newRotation); 987 }, 988 989 setScaleX:function (newScaleX) { 990 this._transformSystemDirty = true; 991 cc.Node.prototype.setScaleX.call(this, newScaleX); 992 }, 993 994 setScaleY:function (newScaleY) { 995 this._transformSystemDirty = true; 996 cc.Node.prototype.setScaleY.call(this, newScaleY); 997 }, 998 999 /** 1000 * get start size in pixels of each particle 1001 * @return {Number} 1002 */ 1003 getStartSize:function () { 1004 return this._startSize; 1005 }, 1006 1007 /** 1008 * set start size in pixels of each particle 1009 * @param {Number} startSize 1010 */ 1011 setStartSize:function (startSize) { 1012 this._startSize = startSize; 1013 }, 1014 1015 /** 1016 * get size variance in pixels of each particle 1017 * @return {Number} 1018 */ 1019 getStartSizeVar:function () { 1020 return this._startSizeVar; 1021 }, 1022 1023 /** 1024 * set size variance in pixels of each particle 1025 * @param {Number} startSizeVar 1026 */ 1027 setStartSizeVar:function (startSizeVar) { 1028 this._startSizeVar = startSizeVar; 1029 }, 1030 1031 /** 1032 * get end size in pixels of each particle 1033 * @return {Number} 1034 */ 1035 getEndSize:function () { 1036 return this._endSize; 1037 }, 1038 1039 /** 1040 * set end size in pixels of each particle 1041 * @param endSize 1042 */ 1043 setEndSize:function (endSize) { 1044 this._endSize = endSize; 1045 }, 1046 1047 /** 1048 * get end size variance in pixels of each particle 1049 * @return {Number} 1050 */ 1051 getEndSizeVar:function () { 1052 return this._endSizeVar; 1053 }, 1054 1055 /** 1056 * set end size variance in pixels of each particle 1057 * @param {Number} endSizeVar 1058 */ 1059 setEndSizeVar:function (endSizeVar) { 1060 this._endSizeVar = endSizeVar; 1061 }, 1062 1063 /** 1064 * set start color of each particle 1065 * @return {cc.Color4F} 1066 */ 1067 getStartColor:function () { 1068 return this._startColor; 1069 }, 1070 1071 /** 1072 * get start color of each particle 1073 * @param {cc.Color4F} startColor 1074 */ 1075 setStartColor:function (startColor) { 1076 if (startColor instanceof cc.Color3B) 1077 startColor = cc.c4FFromccc3B(startColor); 1078 this._startColor = startColor; 1079 }, 1080 1081 /** 1082 * get start color variance of each particle 1083 * @return {cc.Color4F} 1084 */ 1085 getStartColorVar:function () { 1086 return this._startColorVar; 1087 }, 1088 1089 /** 1090 * set start color variance of each particle 1091 * @param {cc.Color4F} startColorVar 1092 */ 1093 setStartColorVar:function (startColorVar) { 1094 if (startColorVar instanceof cc.Color3B) 1095 startColorVar = cc.c4FFromccc3B(startColorVar); 1096 this._startColorVar = startColorVar; 1097 }, 1098 1099 /** 1100 * get end color and end color variation of each particle 1101 * @return {cc.Color4F} 1102 */ 1103 getEndColor:function () { 1104 return this._endColor; 1105 }, 1106 1107 /** 1108 * set end color and end color variation of each particle 1109 * @param {cc.Color4F} endColor 1110 */ 1111 setEndColor:function (endColor) { 1112 if (endColor instanceof cc.Color3B) 1113 endColor = cc.c4FFromccc3B(endColor); 1114 this._endColor = endColor; 1115 }, 1116 1117 /** 1118 * get end color variance of each particle 1119 * @return {cc.Color4F} 1120 */ 1121 getEndColorVar:function () { 1122 return this._endColorVar; 1123 }, 1124 1125 /** 1126 * set end color variance of each particle 1127 * @param {cc.Color4F} endColorVar 1128 */ 1129 setEndColorVar:function (endColorVar) { 1130 if (endColorVar instanceof cc.Color3B) 1131 endColorVar = cc.c4FFromccc3B(endColorVar); 1132 this._endColorVar = endColorVar; 1133 }, 1134 1135 /** 1136 * get initial angle of each particle 1137 * @return {Number} 1138 */ 1139 getStartSpin:function () { 1140 return this._startSpin; 1141 }, 1142 1143 /** 1144 * set initial angle of each particle 1145 * @param {Number} startSpin 1146 */ 1147 setStartSpin:function (startSpin) { 1148 this._startSpin = startSpin; 1149 }, 1150 1151 /** 1152 * get initial angle variance of each particle 1153 * @return {Number} 1154 */ 1155 getStartSpinVar:function () { 1156 return this._startSpinVar; 1157 }, 1158 1159 /** 1160 * set initial angle variance of each particle 1161 * @param {Number} startSpinVar 1162 */ 1163 setStartSpinVar:function (startSpinVar) { 1164 this._startSpinVar = startSpinVar; 1165 }, 1166 1167 /** 1168 * get end angle of each particle 1169 * @return {Number} 1170 */ 1171 getEndSpin:function () { 1172 return this._endSpin; 1173 }, 1174 1175 /** 1176 * set end angle of each particle 1177 * @param {Number} endSpin 1178 */ 1179 setEndSpin:function (endSpin) { 1180 this._endSpin = endSpin; 1181 }, 1182 1183 /** 1184 * get end angle variance of each particle 1185 * @return {Number} 1186 */ 1187 getEndSpinVar:function () { 1188 return this._endSpinVar; 1189 }, 1190 1191 /** 1192 * set end angle variance of each particle 1193 * @param {Number} endSpinVar 1194 */ 1195 setEndSpinVar:function (endSpinVar) { 1196 this._endSpinVar = endSpinVar; 1197 }, 1198 1199 /** 1200 * get emission rate of the particles 1201 * @return {Number} 1202 */ 1203 getEmissionRate:function () { 1204 return this._emissionRate; 1205 }, 1206 1207 /** 1208 * set emission rate of the particles 1209 * @param {Number} emissionRate 1210 */ 1211 setEmissionRate:function (emissionRate) { 1212 this._emissionRate = emissionRate; 1213 }, 1214 1215 /** 1216 * get maximum particles of the system 1217 * @return {Number} 1218 */ 1219 getTotalParticles:function () { 1220 return this._totalParticles; 1221 }, 1222 1223 /** 1224 * set maximum particles of the system 1225 * @param {Number} tp totalParticles 1226 */ 1227 setTotalParticles:function (tp) { 1228 //cc.Assert(tp <= this._allocatedParticles, "Particle: resizing particle array only supported for quads"); 1229 if (cc.renderContextType === cc.CANVAS){ 1230 this._totalParticles = (tp < 200) ? tp : 200; 1231 return; 1232 } 1233 1234 // If we are setting the total numer of particles to a number higher 1235 // than what is allocated, we need to allocate new arrays 1236 if (tp > this._allocatedParticles) { 1237 var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; 1238 // Allocate new memory 1239 this._indices = new Uint16Array(tp * 6); 1240 var locQuadsArrayBuffer = new ArrayBuffer(tp * quadSize); 1241 //TODO need fix 1242 // Assign pointers 1243 var locParticles = []; 1244 var locQuads = []; 1245 for (var j = 0; j < tp; j++) { 1246 locParticles[j] = new cc.Particle(); 1247 locQuads[j] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, j * quadSize); 1248 } 1249 this._allocatedParticles = tp; 1250 this._totalParticles = tp; 1251 1252 // Init particles 1253 if (this._batchNode) { 1254 for (var i = 0; i < tp; i++) 1255 locParticles[i].atlasIndex = i; 1256 } 1257 1258 this._particles = locParticles; 1259 this._quadsArrayBuffer = locQuadsArrayBuffer; 1260 this._quads = locQuads; 1261 1262 this.initIndices(); 1263 //if (cc.TEXTURE_ATLAS_USE_VAO) 1264 // this._setupVBOandVAO(); 1265 //else 1266 this._setupVBO(); 1267 1268 //set the texture coord 1269 if(this._texture){ 1270 var size = this._texture.getContentSize(); 1271 this.initTexCoordsWithRect(cc.rect(0, 0, size.width, size.height)); 1272 } 1273 } else 1274 this._totalParticles = tp; 1275 this.resetSystem(); 1276 }, 1277 1278 /** 1279 * get Texture of Particle System 1280 * @return {cc.Texture2D} 1281 */ 1282 getTexture:function () { 1283 return this._texture; 1284 }, 1285 1286 /** 1287 * set Texture of Particle System 1288 * @param {cc.Texture2D } texture 1289 */ 1290 setTexture:function (texture) { 1291 if(texture.isLoaded()){ 1292 var size = texture.getContentSize(); 1293 this.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height)); 1294 } else { 1295 this._textureLoaded = false; 1296 texture.addLoadedEventListener(function(sender){ 1297 this._textureLoaded = true; 1298 var size = sender.getContentSize(); 1299 this.setTextureWithRect(sender, cc.rect(0, 0, size.width, size.height)); 1300 }, this); 1301 } 1302 }, 1303 1304 /** conforms to CocosNodeTexture protocol */ 1305 /** 1306 * get BlendFunc of Particle System 1307 * @return {cc.BlendFunc} 1308 */ 1309 getBlendFunc:function () { 1310 return this._blendFunc; 1311 }, 1312 1313 /** 1314 * set BlendFunc of Particle System 1315 * @param {Number} src 1316 * @param {Number} dst 1317 */ 1318 setBlendFunc:function (src, dst) { 1319 if (arguments.length == 1) { 1320 if (this._blendFunc != src) { 1321 this._blendFunc = src; 1322 this._updateBlendFunc(); 1323 } 1324 } else { 1325 if (this._blendFunc.src != src || this._blendFunc.dst != dst) { 1326 this._blendFunc = {src:src, dst:dst}; 1327 this._updateBlendFunc(); 1328 } 1329 } 1330 }, 1331 1332 /** 1333 * does the alpha value modify color getter 1334 * @return {Boolean} 1335 */ 1336 getOpacityModifyRGB:function () { 1337 return this._opacityModifyRGB; 1338 }, 1339 1340 /** 1341 * does the alpha value modify color setter 1342 * @param newValue 1343 */ 1344 setOpacityModifyRGB:function (newValue) { 1345 this._opacityModifyRGB = newValue; 1346 }, 1347 1348 /** 1349 * <p>whether or not the particles are using blend additive.<br/> 1350 * If enabled, the following blending function will be used.<br/> 1351 * </p> 1352 * @return {Boolean} 1353 * @example 1354 * source blend function = GL_SRC_ALPHA; 1355 * dest blend function = GL_ONE; 1356 */ 1357 isBlendAdditive:function () { 1358 return (( this._blendFunc.src == gl.SRC_ALPHA && this._blendFunc.dst == gl.ONE) || (this._blendFunc.src == gl.ONE && this._blendFunc.dst == gl.ONE)); 1359 }, 1360 1361 /** 1362 * <p>whether or not the particles are using blend additive.<br/> 1363 * If enabled, the following blending function will be used.<br/> 1364 * </p> 1365 * @param {Boolean} isBlendAdditive 1366 */ 1367 setBlendAdditive:function (isBlendAdditive) { 1368 var locBlendFunc = this._blendFunc; 1369 if (isBlendAdditive) { 1370 locBlendFunc.src = gl.SRC_ALPHA; 1371 locBlendFunc.dst = gl.ONE; 1372 } else { 1373 if (cc.renderContextType === cc.WEBGL) { 1374 if (this._texture && !this._texture.hasPremultipliedAlpha()) { 1375 locBlendFunc.src = gl.SRC_ALPHA; 1376 locBlendFunc.dst = gl.ONE_MINUS_SRC_ALPHA; 1377 } else { 1378 locBlendFunc.src = cc.BLEND_SRC; 1379 locBlendFunc.dst = cc.BLEND_DST; 1380 } 1381 } else { 1382 locBlendFunc.src = cc.BLEND_SRC; 1383 locBlendFunc.dst = cc.BLEND_DST; 1384 } 1385 } 1386 }, 1387 1388 /** 1389 * get particles movement type: Free or Grouped 1390 * @return {Number} 1391 */ 1392 getPositionType:function () { 1393 return this._positionType; 1394 }, 1395 1396 /** 1397 * set particles movement type: Free or Grouped 1398 * @param {Number} positionType 1399 */ 1400 setPositionType:function (positionType) { 1401 this._positionType = positionType; 1402 }, 1403 1404 /** 1405 * <p> return whether or not the node will be auto-removed when it has no particles left.<br/> 1406 * By default it is false.<br/> 1407 * </p> 1408 * @return {Boolean} 1409 */ 1410 isAutoRemoveOnFinish:function () { 1411 return this._isAutoRemoveOnFinish; 1412 }, 1413 1414 /** 1415 * <p> set whether or not the node will be auto-removed when it has no particles left.<br/> 1416 * By default it is false.<br/> 1417 * </p> 1418 * @param {Boolean} isAutoRemoveOnFinish 1419 */ 1420 setAutoRemoveOnFinish:function (isAutoRemoveOnFinish) { 1421 this._isAutoRemoveOnFinish = isAutoRemoveOnFinish; 1422 }, 1423 1424 /** 1425 * return kind of emitter modes 1426 * @return {Number} 1427 */ 1428 getEmitterMode:function () { 1429 return this._emitterMode; 1430 }, 1431 1432 /** 1433 * <p>Switch between different kind of emitter modes:<br/> 1434 * - CCPARTICLE_MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration<br/> 1435 * - CCPARTICLE_MODE_RADIUS: uses radius movement + rotation <br/> 1436 * </p> 1437 * @param {Number} emitterMode 1438 */ 1439 setEmitterMode:function (emitterMode) { 1440 this._emitterMode = emitterMode; 1441 }, 1442 1443 /** 1444 * initializes a cc.ParticleSystem 1445 */ 1446 init:function () { 1447 return this.initWithTotalParticles(150); 1448 }, 1449 1450 /** 1451 * <p> 1452 * initializes a CCParticleSystem from a plist file. <br/> 1453 * This plist files can be creted manually or with Particle Designer:<br/> 1454 * http://particledesigner.71squared.com/ 1455 * </p> 1456 * @param {String} plistFile 1457 * @return {boolean} 1458 */ 1459 initWithFile:function (plistFile) { 1460 this._plistFile = plistFile; 1461 var dict = cc.FileUtils.getInstance().dictionaryWithContentsOfFileThreadSafe(this._plistFile); 1462 1463 cc.Assert(dict != null, "Particles: file not found"); 1464 1465 // XXX compute path from a path, should define a function somewhere to do it 1466 return this.initWithDictionary(dict, ""); 1467 }, 1468 1469 /** 1470 * return bounding box of particle system in world space 1471 * @return {cc.Rect} 1472 */ 1473 getBoundingBoxToWorld:function () { 1474 return cc.rect(0, 0, cc.canvas.width, cc.canvas.height); 1475 }, 1476 1477 /** 1478 * initializes a particle system from a NSDictionary and the path from where to load the png 1479 * @param {object} dictionary 1480 * @param {String} dirname 1481 * @return {Boolean} 1482 */ 1483 initWithDictionary:function (dictionary, dirname) { 1484 var ret = false; 1485 var buffer = null; 1486 var image = null; 1487 var locValueForKey = this._valueForKey; 1488 1489 var maxParticles = parseInt(locValueForKey("maxParticles", dictionary)); 1490 // self, not super 1491 if (this.initWithTotalParticles(maxParticles)) { 1492 // angle 1493 this._angle = parseFloat(locValueForKey("angle", dictionary)); 1494 this._angleVar = parseFloat(locValueForKey("angleVariance", dictionary)); 1495 1496 // duration 1497 this._duration = parseFloat(locValueForKey("duration", dictionary)); 1498 1499 // blend function 1500 this._blendFunc.src = parseInt(locValueForKey("blendFuncSource", dictionary)); 1501 this._blendFunc.dst = parseInt(locValueForKey("blendFuncDestination", dictionary)); 1502 1503 // color 1504 var locStartColor = this._startColor; 1505 locStartColor.r = parseFloat(locValueForKey("startColorRed", dictionary)); 1506 locStartColor.g = parseFloat(locValueForKey("startColorGreen", dictionary)); 1507 locStartColor.b = parseFloat(locValueForKey("startColorBlue", dictionary)); 1508 locStartColor.a = parseFloat(locValueForKey("startColorAlpha", dictionary)); 1509 1510 var locStartColorVar = this._startColorVar; 1511 locStartColorVar.r = parseFloat(locValueForKey("startColorVarianceRed", dictionary)); 1512 locStartColorVar.g = parseFloat(locValueForKey("startColorVarianceGreen", dictionary)); 1513 locStartColorVar.b = parseFloat(locValueForKey("startColorVarianceBlue", dictionary)); 1514 locStartColorVar.a = parseFloat(locValueForKey("startColorVarianceAlpha", dictionary)); 1515 1516 var locEndColor = this._endColor; 1517 locEndColor.r = parseFloat(locValueForKey("finishColorRed", dictionary)); 1518 locEndColor.g = parseFloat(locValueForKey("finishColorGreen", dictionary)); 1519 locEndColor.b = parseFloat(locValueForKey("finishColorBlue", dictionary)); 1520 locEndColor.a = parseFloat(locValueForKey("finishColorAlpha", dictionary)); 1521 1522 var locEndColorVar = this._endColorVar; 1523 locEndColorVar.r = parseFloat(locValueForKey("finishColorVarianceRed", dictionary)); 1524 locEndColorVar.g = parseFloat(locValueForKey("finishColorVarianceGreen", dictionary)); 1525 locEndColorVar.b = parseFloat(locValueForKey("finishColorVarianceBlue", dictionary)); 1526 locEndColorVar.a = parseFloat(locValueForKey("finishColorVarianceAlpha", dictionary)); 1527 1528 // particle size 1529 this._startSize = parseFloat(locValueForKey("startParticleSize", dictionary)); 1530 this._startSizeVar = parseFloat(locValueForKey("startParticleSizeVariance", dictionary)); 1531 this._endSize = parseFloat(locValueForKey("finishParticleSize", dictionary)); 1532 this._endSizeVar = parseFloat(locValueForKey("finishParticleSizeVariance", dictionary)); 1533 1534 // position 1535 var x = parseFloat(locValueForKey("sourcePositionx", dictionary)); 1536 var y = parseFloat(locValueForKey("sourcePositiony", dictionary)); 1537 this.setPosition(x, y); 1538 this._posVar.x = parseFloat(locValueForKey("sourcePositionVariancex", dictionary)); 1539 this._posVar.y = parseFloat(locValueForKey("sourcePositionVariancey", dictionary)); 1540 1541 // Spinning 1542 this._startSpin = parseFloat(locValueForKey("rotationStart", dictionary)); 1543 this._startSpinVar = parseFloat(locValueForKey("rotationStartVariance", dictionary)); 1544 this._endSpin = parseFloat(locValueForKey("rotationEnd", dictionary)); 1545 this._endSpinVar = parseFloat(locValueForKey("rotationEndVariance", dictionary)); 1546 1547 this._emitterMode = parseInt(locValueForKey("emitterType", dictionary)); 1548 1549 // Mode A: Gravity + tangential accel + radial accel 1550 if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) { 1551 var locModeA = this.modeA; 1552 // gravity 1553 locModeA.gravity.x = parseFloat(locValueForKey("gravityx", dictionary)); 1554 locModeA.gravity.y = parseFloat(locValueForKey("gravityy", dictionary)); 1555 1556 // speed 1557 locModeA.speed = parseFloat(locValueForKey("speed", dictionary)); 1558 locModeA.speedVar = parseFloat(locValueForKey("speedVariance", dictionary)); 1559 1560 // radial acceleration 1561 var pszTmp = locValueForKey("radialAcceleration", dictionary); 1562 locModeA.radialAccel = (pszTmp) ? parseFloat(pszTmp) : 0; 1563 1564 pszTmp = locValueForKey("radialAccelVariance", dictionary); 1565 locModeA.radialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0; 1566 1567 // tangential acceleration 1568 pszTmp = locValueForKey("tangentialAcceleration", dictionary); 1569 locModeA.tangentialAccel = (pszTmp) ? parseFloat(pszTmp) : 0; 1570 1571 pszTmp = locValueForKey("tangentialAccelVariance", dictionary); 1572 locModeA.tangentialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0; 1573 1574 // rotation is dir 1575 var locRotationIsDir = locValueForKey("rotationIsDir", dictionary).toLowerCase(); 1576 locModeA.rotationIsDir = (locRotationIsDir != null && (locRotationIsDir === "true" || locRotationIsDir === "1")); 1577 } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) { 1578 // or Mode B: radius movement 1579 var locModeB = this.modeB; 1580 locModeB.startRadius = parseFloat(locValueForKey("maxRadius", dictionary)); 1581 locModeB.startRadiusVar = parseFloat(locValueForKey("maxRadiusVariance", dictionary)); 1582 locModeB.endRadius = parseFloat(locValueForKey("minRadius", dictionary)); 1583 locModeB.endRadiusVar = 0; 1584 locModeB.rotatePerSecond = parseFloat(locValueForKey("rotatePerSecond", dictionary)); 1585 locModeB.rotatePerSecondVar = parseFloat(locValueForKey("rotatePerSecondVariance", dictionary)); 1586 } else { 1587 cc.Assert(false, "Invalid emitterType in config file"); 1588 return false; 1589 } 1590 1591 // life span 1592 this._life = parseFloat(locValueForKey("particleLifespan", dictionary)); 1593 this._lifeVar = parseFloat(locValueForKey("particleLifespanVariance", dictionary)); 1594 1595 // emission Rate 1596 this._emissionRate = this._totalParticles / this._life; 1597 1598 //don't get the internal texture if a batchNode is used 1599 if (!this._batchNode) { 1600 // Set a compatible default for the alpha transfer 1601 this._opacityModifyRGB = false; 1602 1603 // texture 1604 // Try to get the texture from the cache 1605 var textureName = locValueForKey("textureFileName", dictionary); 1606 var fullpath = cc.FileUtils.getInstance().fullPathFromRelativeFile(textureName, this._plistFile); 1607 1608 var tex = cc.TextureCache.getInstance().textureForKey(fullpath); 1609 1610 if (tex) { 1611 this.setTexture(tex); 1612 } else { 1613 var textureData = locValueForKey("textureImageData", dictionary); 1614 1615 if (textureData && textureData.length == 0) { 1616 cc.Assert(textureData, "cc.ParticleSystem.initWithDictory:textureImageData is null"); 1617 tex = cc.TextureCache.getInstance().addImage(fullpath); 1618 if (!tex) 1619 return false; 1620 this.setTexture(tex); 1621 } else { 1622 buffer = cc.unzipBase64AsArray(textureData, 1); 1623 if (!buffer) { 1624 cc.log("cc.ParticleSystem: error decoding or ungzipping textureImageData"); 1625 return false; 1626 } 1627 1628 var imageFormat = cc.getImageFormatByData(buffer); 1629 1630 if(imageFormat !== cc.FMT_TIFF && imageFormat !== cc.FMT_PNG){ 1631 cc.log("cc.ParticleSystem: unknown image format with Data"); 1632 return false; 1633 } 1634 1635 var canvasObj = document.createElement("canvas"); 1636 if(imageFormat === cc.FMT_PNG){ 1637 var myPngObj = new cc.PNGReader(buffer); 1638 myPngObj.render(canvasObj); 1639 1640 } else { 1641 var myTIFFObj = cc.TIFFReader.getInstance(); 1642 myTIFFObj.parseTIFF(buffer,canvasObj); 1643 } 1644 1645 cc.TextureCache.getInstance().cacheImage(fullpath, canvasObj); 1646 1647 var addTexture = cc.TextureCache.getInstance().textureForKey(fullpath); 1648 1649 cc.Assert(addTexture != null, "cc.ParticleSystem: error loading the texture"); 1650 1651 this.setTexture(addTexture); 1652 } 1653 } 1654 1655 } 1656 ret = true; 1657 } 1658 return ret; 1659 }, 1660 1661 /** 1662 * Initializes a system with a fixed number of particles 1663 * @param {Number} numberOfParticles 1664 * @return {Boolean} 1665 */ 1666 initWithTotalParticles:function (numberOfParticles) { 1667 this._totalParticles = numberOfParticles; 1668 1669 var i; 1670 this._particles = []; 1671 for(i = 0; i< numberOfParticles; i++){ 1672 this._particles[i] = new cc.Particle(); 1673 } 1674 1675 if (!this._particles) { 1676 cc.log("Particle system: not enough memory"); 1677 return false; 1678 } 1679 this._allocatedParticles = numberOfParticles; 1680 1681 if (this._batchNode) 1682 for (i = 0; i < this._totalParticles; i++) 1683 this._particles[i].atlasIndex = i; 1684 1685 // default, active 1686 this._isActive = true; 1687 1688 // default blend function 1689 this._blendFunc.src = cc.BLEND_SRC; 1690 this._blendFunc.dst = cc.BLEND_DST; 1691 1692 // default movement type; 1693 this._positionType = cc.PARTICLE_TYPE_FREE; 1694 1695 // by default be in mode A: 1696 this._emitterMode = cc.PARTICLE_MODE_GRAVITY; 1697 1698 // default: modulate 1699 // XXX: not used 1700 // colorModulate = YES; 1701 this._isAutoRemoveOnFinish = false; 1702 1703 // Optimization: compile udpateParticle method 1704 //updateParticleSel = @selector(updateQuadWithParticle:newPosition:); 1705 //updateParticleImp = (CC_UPDATE_PARTICLE_IMP) [self methodForSelector:updateParticleSel]; 1706 1707 //for batchNode 1708 this._transformSystemDirty = false; 1709 1710 // udpate after action in run! 1711 this.scheduleUpdateWithPriority(1); 1712 1713 if(cc.renderContextType === cc.WEBGL){ 1714 // allocating data space 1715 if (!this._allocMemory()) 1716 return false; 1717 1718 this.initIndices(); 1719 //if (cc.TEXTURE_ATLAS_USE_VAO) 1720 // this._setupVBOandVAO(); 1721 //else 1722 this._setupVBO(); 1723 1724 this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_TEXTURECOLOR)); 1725 } 1726 1727 return true; 1728 }, 1729 1730 destroyParticleSystem:function () { 1731 this.unscheduleUpdate(); 1732 }, 1733 1734 /** 1735 * Add a particle to the emitter 1736 * @return {Boolean} 1737 */ 1738 addParticle: function () { 1739 if (this.isFull()) 1740 return false; 1741 var particle, particles = this._particles; 1742 if (cc.renderContextType === cc.CANVAS) { 1743 if (this._particleCount < particles.length) { 1744 particle = particles[this._particleCount]; 1745 } else { 1746 particle = new cc.Particle(); 1747 particles.push(particle); 1748 } 1749 } else { 1750 particle = particles[this._particleCount]; 1751 } 1752 this.initParticle(particle); 1753 ++this._particleCount; 1754 return true; 1755 }, 1756 1757 /** 1758 * Initializes a particle 1759 * @param {cc.Particle} particle 1760 */ 1761 initParticle:function (particle) { 1762 var locRandomMinus11 = cc.RANDOM_MINUS1_1; 1763 // timeToLive 1764 // no negative life. prevent division by 0 1765 particle.timeToLive = this._life + this._lifeVar * locRandomMinus11(); 1766 particle.timeToLive = Math.max(0, particle.timeToLive); 1767 1768 // position 1769 particle.pos.x = this._sourcePosition.x + this._posVar.x * locRandomMinus11(); 1770 particle.pos.y = this._sourcePosition.y + this._posVar.y * locRandomMinus11(); 1771 1772 // Color 1773 var start, end; 1774 var locStartColor = this._startColor, locStartColorVar = this._startColorVar; 1775 var locEndColor = this._endColor, locEndColorVar = this._endColorVar; 1776 if (cc.renderContextType === cc.CANVAS) { 1777 start = new cc.Color4F( 1778 cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 1), 1779 cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 1), 1780 cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 1), 1781 cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 1) 1782 ); 1783 end = new cc.Color4F( 1784 cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 1), 1785 cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 1), 1786 cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 1), 1787 cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 1) 1788 ); 1789 } else { 1790 start = { 1791 r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 1), 1792 g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 1), 1793 b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 1), 1794 a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 1) 1795 }; 1796 end = { 1797 r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 1), 1798 g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 1), 1799 b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 1), 1800 a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 1) 1801 }; 1802 } 1803 1804 particle.color = start; 1805 var locParticleDeltaColor = particle.deltaColor, locParticleTimeToLive = particle.timeToLive; 1806 locParticleDeltaColor.r = (end.r - start.r) / locParticleTimeToLive; 1807 locParticleDeltaColor.g = (end.g - start.g) / locParticleTimeToLive; 1808 locParticleDeltaColor.b = (end.b - start.b) / locParticleTimeToLive; 1809 locParticleDeltaColor.a = (end.a - start.a) / locParticleTimeToLive; 1810 1811 // size 1812 var startS = this._startSize + this._startSizeVar * locRandomMinus11(); 1813 startS = Math.max(0, startS); // No negative value 1814 1815 particle.size = startS; 1816 if (this._endSize === cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE) { 1817 particle.deltaSize = 0; 1818 } else { 1819 var endS = this._endSize + this._endSizeVar * locRandomMinus11(); 1820 endS = Math.max(0, endS); // No negative values 1821 particle.deltaSize = (endS - startS) / locParticleTimeToLive; 1822 } 1823 1824 // rotation 1825 var startA = this._startSpin + this._startSpinVar * locRandomMinus11(); 1826 var endA = this._endSpin + this._endSpinVar * locRandomMinus11(); 1827 particle.rotation = startA; 1828 particle.deltaRotation = (endA - startA) / locParticleTimeToLive; 1829 1830 // position 1831 if (this._positionType == cc.PARTICLE_TYPE_FREE) 1832 particle.startPos = this.convertToWorldSpace(this._pointZeroForParticle); 1833 else if (this._positionType == cc.PARTICLE_TYPE_RELATIVE) 1834 particle.startPos = this._position; 1835 1836 // direction 1837 var a = cc.DEGREES_TO_RADIANS(this._angle + this._angleVar * locRandomMinus11()); 1838 1839 // Mode Gravity: A 1840 if (this._emitterMode === cc.PARTICLE_MODE_GRAVITY) { 1841 var locModeA = this.modeA, locParticleModeA = particle.modeA; 1842 var s = locModeA.speed + locModeA.speedVar * locRandomMinus11(); 1843 1844 // direction 1845 locParticleModeA.dir.x = Math.cos(a); 1846 locParticleModeA.dir.y = Math.sin(a); 1847 cc.pMultIn(locParticleModeA.dir, s); 1848 1849 // radial accel 1850 locParticleModeA.radialAccel = locModeA.radialAccel + locModeA.radialAccelVar * locRandomMinus11(); 1851 1852 // tangential accel 1853 locParticleModeA.tangentialAccel = locModeA.tangentialAccel + locModeA.tangentialAccelVar * locRandomMinus11(); 1854 1855 // rotation is dir 1856 if(locModeA.rotationIsDir) 1857 particle.rotation = -cc.RADIANS_TO_DEGREES(cc.pToAngle(locParticleModeA.dir)); 1858 } else { 1859 // Mode Radius: B 1860 var locModeB = this.modeB, locParitlceModeB = particle.modeB; 1861 1862 // Set the default diameter of the particle from the source position 1863 var startRadius = locModeB.startRadius + locModeB.startRadiusVar * locRandomMinus11(); 1864 var endRadius = locModeB.endRadius + locModeB.endRadiusVar * locRandomMinus11(); 1865 1866 locParitlceModeB.radius = startRadius; 1867 locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive; 1868 1869 locParitlceModeB.angle = a; 1870 locParitlceModeB.degreesPerSecond = cc.DEGREES_TO_RADIANS(locModeB.rotatePerSecond + locModeB.rotatePerSecondVar * locRandomMinus11()); 1871 } 1872 }, 1873 1874 /** 1875 * stop emitting particles. Running particles will continue to run until they die 1876 */ 1877 stopSystem:function () { 1878 this._isActive = false; 1879 this._elapsed = this._duration; 1880 this._emitCounter = 0; 1881 }, 1882 1883 /** 1884 * Kill all living particles. 1885 */ 1886 resetSystem:function () { 1887 this._isActive = true; 1888 this._elapsed = 0; 1889 var locParticles = this._particles; 1890 for (this._particleIdx = 0; this._particleIdx < this._particleCount; ++this._particleIdx) 1891 locParticles[this._particleIdx].timeToLive = 0 ; 1892 }, 1893 1894 /** 1895 * whether or not the system is full 1896 * @return {Boolean} 1897 */ 1898 isFull:function () { 1899 return (this._particleCount >= this._totalParticles); 1900 }, 1901 1902 /** 1903 * should be overridden by subclasses 1904 * @param {cc.Particle} particle 1905 * @param {cc.Point} newPosition 1906 */ 1907 updateQuadWithParticle:function (particle, newPosition) { 1908 var quad = null; 1909 if (this._batchNode) { 1910 var batchQuads = this._batchNode.getTextureAtlas().getQuads(); 1911 quad = batchQuads[this._atlasIndex + particle.atlasIndex]; 1912 this._batchNode.getTextureAtlas()._dirty = true; 1913 } else 1914 quad = this._quads[this._particleIdx]; 1915 1916 var r, g, b, a; 1917 if(this._opacityModifyRGB){ 1918 r = 0 | (particle.color.r * particle.color.a * 255); 1919 g = 0 | (particle.color.g * particle.color.a * 255); 1920 b = 0 | (particle.color.b * particle.color.a * 255); 1921 a = 0 | (particle.color.a * 255); 1922 }else{ 1923 r = 0 | (particle.color.r * 255); 1924 g = 0 | (particle.color.g * 255); 1925 b = 0 | (particle.color.b * 255); 1926 a = 0 | (particle.color.a * 255); 1927 } 1928 1929 var locColors = quad.bl.colors; 1930 locColors.r = r; 1931 locColors.g = g; 1932 locColors.b = b; 1933 locColors.a = a; 1934 1935 locColors = quad.br.colors; 1936 locColors.r = r; 1937 locColors.g = g; 1938 locColors.b = b; 1939 locColors.a = a; 1940 1941 locColors = quad.tl.colors; 1942 locColors.r = r; 1943 locColors.g = g; 1944 locColors.b = b; 1945 locColors.a = a; 1946 1947 locColors = quad.tr.colors; 1948 locColors.r = r; 1949 locColors.g = g; 1950 locColors.b = b; 1951 locColors.a = a; 1952 1953 // vertices 1954 var size_2 = particle.size / 2; 1955 if (particle.rotation) { 1956 var x1 = -size_2; 1957 var y1 = -size_2; 1958 1959 var x2 = size_2; 1960 var y2 = size_2; 1961 var x = newPosition.x; 1962 var y = newPosition.y; 1963 1964 var rad = -cc.DEGREES_TO_RADIANS(particle.rotation); 1965 var cr = Math.cos(rad); 1966 var sr = Math.sin(rad); 1967 var ax = x1 * cr - y1 * sr + x; 1968 var ay = x1 * sr + y1 * cr + y; 1969 var bx = x2 * cr - y1 * sr + x; 1970 var by = x2 * sr + y1 * cr + y; 1971 var cx = x2 * cr - y2 * sr + x; 1972 var cy = x2 * sr + y2 * cr + y; 1973 var dx = x1 * cr - y2 * sr + x; 1974 var dy = x1 * sr + y2 * cr + y; 1975 1976 // bottom-left 1977 quad.bl.vertices.x = ax; 1978 quad.bl.vertices.y = ay; 1979 1980 // bottom-right vertex: 1981 quad.br.vertices.x = bx; 1982 quad.br.vertices.y = by; 1983 1984 // top-left vertex: 1985 quad.tl.vertices.x = dx; 1986 quad.tl.vertices.y = dy; 1987 1988 // top-right vertex: 1989 quad.tr.vertices.x = cx; 1990 quad.tr.vertices.y = cy; 1991 } else { 1992 // bottom-left vertex: 1993 quad.bl.vertices.x = newPosition.x - size_2; 1994 quad.bl.vertices.y = newPosition.y - size_2; 1995 1996 // bottom-right vertex: 1997 quad.br.vertices.x = newPosition.x + size_2; 1998 quad.br.vertices.y = newPosition.y - size_2; 1999 2000 // top-left vertex: 2001 quad.tl.vertices.x = newPosition.x - size_2; 2002 quad.tl.vertices.y = newPosition.y + size_2; 2003 2004 // top-right vertex: 2005 quad.tr.vertices.x = newPosition.x + size_2; 2006 quad.tr.vertices.y = newPosition.y + size_2; 2007 } 2008 }, 2009 2010 /** 2011 * should be overridden by subclasses 2012 */ 2013 postStep:function () { 2014 if (cc.renderContextType === cc.WEBGL) { 2015 var gl = cc.renderContext; 2016 2017 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2018 gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); 2019 2020 // Option 2: Data 2021 // glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * particleCount, quads_, GL_DYNAMIC_DRAW); 2022 2023 // Option 3: Orphaning + glMapBuffer 2024 // glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*m_uTotalParticles, NULL, GL_STREAM_DRAW); 2025 // void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); 2026 // memcpy(buf, m_pQuads, sizeof(m_pQuads[0])*m_uTotalParticles); 2027 // glUnmapBuffer(GL_ARRAY_BUFFER); 2028 2029 //cc.CHECK_GL_ERROR_DEBUG(); 2030 } 2031 }, 2032 2033 /** 2034 * update emitter's status 2035 * @override 2036 * @param {Number} dt delta time 2037 */ 2038 update:function (dt) { 2039 if (this._isActive && this._emissionRate) { 2040 var rate = 1.0 / this._emissionRate; 2041 //issue #1201, prevent bursts of particles, due to too high emitCounter 2042 if (this._particleCount < this._totalParticles) 2043 this._emitCounter += dt; 2044 2045 while ((this._particleCount < this._totalParticles) && (this._emitCounter > rate)) { 2046 this.addParticle(); 2047 this._emitCounter -= rate; 2048 } 2049 2050 this._elapsed += dt; 2051 if (this._duration != -1 && this._duration < this._elapsed) 2052 this.stopSystem(); 2053 } 2054 this._particleIdx = 0; 2055 2056 var currentPosition = cc.Particle.TemporaryPoints[0]; 2057 if (this._positionType == cc.PARTICLE_TYPE_FREE) { 2058 cc.pIn(currentPosition, this.convertToWorldSpace(this._pointZeroForParticle)); 2059 2060 } else if (this._positionType == cc.PARTICLE_TYPE_RELATIVE) { 2061 currentPosition.x = this._position.x; 2062 currentPosition.y = this._position.y; 2063 } 2064 2065 if (this._visible) { 2066 2067 // Used to reduce memory allocation / creation within the loop 2068 var tpa = cc.Particle.TemporaryPoints[1], 2069 tpb = cc.Particle.TemporaryPoints[2], 2070 tpc = cc.Particle.TemporaryPoints[3]; 2071 2072 var locParticles = this._particles; 2073 while (this._particleIdx < this._particleCount) { 2074 2075 // Reset the working particles 2076 cc.pZeroIn(tpa); 2077 cc.pZeroIn(tpb); 2078 cc.pZeroIn(tpc); 2079 2080 var selParticle = locParticles[this._particleIdx]; 2081 2082 // life 2083 selParticle.timeToLive -= dt; 2084 2085 if (selParticle.timeToLive > 0) { 2086 // Mode A: gravity, direction, tangential accel & radial accel 2087 if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) { 2088 2089 var tmp = tpc, radial = tpa, tangential = tpb; 2090 2091 // radial acceleration 2092 if (selParticle.pos.x || selParticle.pos.y) { 2093 cc.pIn(radial, selParticle.pos); 2094 cc.pNormalizeIn(radial); 2095 } else { 2096 cc.pZeroIn(radial); 2097 } 2098 2099 cc.pIn(tangential, radial); 2100 cc.pMultIn(radial, selParticle.modeA.radialAccel); 2101 2102 // tangential acceleration 2103 var newy = tangential.x; 2104 tangential.x = -tangential.y; 2105 tangential.y = newy; 2106 2107 cc.pMultIn(tangential, selParticle.modeA.tangentialAccel); 2108 2109 cc.pIn(tmp, radial); 2110 cc.pAddIn(tmp, tangential); 2111 cc.pAddIn(tmp, this.modeA.gravity); 2112 cc.pMultIn(tmp, dt); 2113 cc.pAddIn(selParticle.modeA.dir, tmp); 2114 2115 2116 cc.pIn(tmp, selParticle.modeA.dir); 2117 cc.pMultIn(tmp, dt); 2118 cc.pAddIn(selParticle.pos, tmp); 2119 2120 } else { 2121 // Mode B: radius movement 2122 var selModeB = selParticle.modeB; 2123 // Update the angle and radius of the particle. 2124 selModeB.angle += selModeB.degreesPerSecond * dt; 2125 selModeB.radius += selModeB.deltaRadius * dt; 2126 2127 selParticle.pos.x = -Math.cos(selModeB.angle) * selModeB.radius; 2128 selParticle.pos.y = -Math.sin(selModeB.angle) * selModeB.radius; 2129 } 2130 2131 // color 2132 if (!this._dontTint) { 2133 selParticle.color.r += (selParticle.deltaColor.r * dt); 2134 selParticle.color.g += (selParticle.deltaColor.g * dt); 2135 selParticle.color.b += (selParticle.deltaColor.b * dt); 2136 selParticle.color.a += (selParticle.deltaColor.a * dt); 2137 selParticle.isChangeColor = true; 2138 } 2139 2140 // size 2141 selParticle.size += (selParticle.deltaSize * dt); 2142 selParticle.size = Math.max(0, selParticle.size); 2143 2144 // angle 2145 selParticle.rotation += (selParticle.deltaRotation * dt); 2146 2147 // 2148 // update values in quad 2149 // 2150 var newPos = tpa; 2151 if (this._positionType == cc.PARTICLE_TYPE_FREE || this._positionType == cc.PARTICLE_TYPE_RELATIVE) { 2152 2153 var diff = tpb; 2154 cc.pIn(diff, currentPosition); 2155 cc.pSubIn(diff, selParticle.startPos); 2156 2157 cc.pIn(newPos, selParticle.pos); 2158 cc.pSubIn(newPos, diff); 2159 2160 } else { 2161 cc.pIn(newPos, selParticle.pos); 2162 } 2163 2164 // translate newPos to correct position, since matrix transform isn't performed in batchnode 2165 // don't update the particle with the new position information, it will interfere with the radius and tangential calculations 2166 if (this._batchNode) { 2167 newPos.x += this._position.x; 2168 newPos.y += this._position.y; 2169 } 2170 2171 if (cc.renderContextType == cc.WEBGL) { 2172 // IMPORTANT: newPos may not be used as a reference here! (as it is just the temporary tpa point) 2173 // the implementation of updateQuadWithParticle must use 2174 // the x and y values directly 2175 this.updateQuadWithParticle(selParticle, newPos); 2176 } else { 2177 cc.pIn(selParticle.drawPos, newPos); 2178 } 2179 //updateParticleImp(self, updateParticleSel, p, newPos); 2180 2181 // update particle counter 2182 ++this._particleIdx; 2183 } else { 2184 // life < 0 2185 var currentIndex = selParticle.atlasIndex; 2186 if(this._particleIdx !== this._particleCount -1){ 2187 var deadParticle = locParticles[this._particleIdx]; 2188 locParticles[this._particleIdx] = locParticles[this._particleCount -1]; 2189 locParticles[this._particleCount -1] = deadParticle; 2190 } 2191 if (this._batchNode) { 2192 //disable the switched particle 2193 this._batchNode.disableParticle(this._atlasIndex + currentIndex); 2194 2195 //switch indexes 2196 locParticles[this._particleCount - 1].atlasIndex = currentIndex; 2197 } 2198 2199 --this._particleCount; 2200 if (this._particleCount == 0 && this._isAutoRemoveOnFinish) { 2201 this.unscheduleUpdate(); 2202 this._parent.removeChild(this, true); 2203 return; 2204 } 2205 } 2206 } 2207 this._transformSystemDirty = false; 2208 } 2209 2210 if (!this._batchNode) 2211 this.postStep(); 2212 }, 2213 2214 updateWithNoTime:function () { 2215 this.update(0); 2216 }, 2217 2218 /** 2219 * return the string found by key in dict. 2220 * @param {string} key 2221 * @param {object} dict 2222 * @return {String} "" if not found; return the string if found. 2223 * @private 2224 */ 2225 _valueForKey:function (key, dict) { 2226 if (dict) { 2227 var pString = dict[key]; 2228 return pString != null ? pString : ""; 2229 } 2230 return ""; 2231 }, 2232 2233 _updateBlendFunc:function () { 2234 cc.Assert(!this._batchNode, "Can't change blending functions when the particle is being batched"); 2235 2236 var locTexture = this._texture; 2237 if (locTexture && locTexture instanceof cc.Texture2D) { 2238 this._opacityModifyRGB = false; 2239 var locBlendFunc = this._blendFunc; 2240 if (locBlendFunc.src == cc.BLEND_SRC && locBlendFunc.dst == cc.BLEND_DST) { 2241 if (locTexture.hasPremultipliedAlpha()) { 2242 this._opacityModifyRGB = true; 2243 } else { 2244 locBlendFunc.src = gl.SRC_ALPHA; 2245 locBlendFunc.dst = gl.ONE_MINUS_SRC_ALPHA; 2246 } 2247 } 2248 } 2249 }, 2250 2251 clone:function () { 2252 var retParticle = new cc.ParticleSystem(); 2253 2254 // self, not super 2255 if (retParticle.initWithTotalParticles(this._totalParticles)) { 2256 // angle 2257 retParticle._angle = this._angle; 2258 retParticle._angleVar = this._angleVar; 2259 2260 // duration 2261 retParticle._duration = this._duration; 2262 2263 // blend function 2264 retParticle._blendFunc.src = this._blendFunc.src; 2265 retParticle._blendFunc.dst = this._blendFunc.dst; 2266 2267 // color 2268 var particleStartColor = retParticle._startColor, locStartColor = this._startColor; 2269 particleStartColor.r = locStartColor.r; 2270 particleStartColor.g = locStartColor.g; 2271 particleStartColor.b = locStartColor.b; 2272 particleStartColor.a = locStartColor.a; 2273 2274 var particleStartColorVar = retParticle._startColorVar, locStartColorVar = this._startColorVar; 2275 particleStartColorVar.r = locStartColorVar.r; 2276 particleStartColorVar.g = locStartColorVar.g; 2277 particleStartColorVar.b = locStartColorVar.b; 2278 particleStartColorVar.a = locStartColorVar.a; 2279 2280 var particleEndColor = retParticle._endColor, locEndColor = this._endColor; 2281 particleEndColor.r = locEndColor.r; 2282 particleEndColor.g = locEndColor.g; 2283 particleEndColor.b = locEndColor.b; 2284 particleEndColor.a = locEndColor.a; 2285 2286 var particleEndColorVar = retParticle._endColorVar, locEndColorVar = this._endColorVar; 2287 particleEndColorVar.r = locEndColorVar.r; 2288 particleEndColorVar.g = locEndColorVar.g; 2289 particleEndColorVar.b = locEndColorVar.b; 2290 particleEndColorVar.a = locEndColorVar.a; 2291 2292 // particle size 2293 retParticle._startSize = this._startSize; 2294 retParticle._startSizeVar = this._startSizeVar; 2295 retParticle._endSize = this._endSize; 2296 retParticle._endSizeVar = this._endSizeVar; 2297 2298 // position 2299 retParticle.setPosition(new cc.Point(this._position.x, this._position.y)); 2300 retParticle._posVar.x = this._posVar.x; 2301 retParticle._posVar.y = this._posVar.y; 2302 2303 // Spinning 2304 retParticle._startSpin = this._startSpin; 2305 retParticle._startSpinVar = this._startSpinVar; 2306 retParticle._endSpin = this._endSpin; 2307 retParticle._endSpinVar = this._endSpinVar; 2308 2309 retParticle._emitterMode = this._emitterMode; 2310 2311 // Mode A: Gravity + tangential accel + radial accel 2312 if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) { 2313 var particleModeA = retParticle.modeA, locModeA = this.modeA; 2314 // gravity 2315 particleModeA.gravity.x = locModeA.gravity.x; 2316 particleModeA.gravity.y = locModeA.gravity.y; 2317 2318 // speed 2319 particleModeA.speed = locModeA.speed; 2320 particleModeA.speedVar = locModeA.speedVar; 2321 2322 // radial acceleration 2323 particleModeA.radialAccel = locModeA.radialAccel; 2324 2325 particleModeA.radialAccelVar = locModeA.radialAccelVar; 2326 2327 // tangential acceleration 2328 particleModeA.tangentialAccel = locModeA.tangentialAccel; 2329 2330 particleModeA.tangentialAccelVar = locModeA.tangentialAccelVar; 2331 } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) { 2332 var particleModeB = retParticle.modeB, locModeB = this.modeB; 2333 // or Mode B: radius movement 2334 particleModeB.startRadius = locModeB.startRadius; 2335 particleModeB.startRadiusVar = locModeB.startRadiusVar; 2336 particleModeB.endRadius = locModeB.endRadius; 2337 particleModeB.endRadiusVar = locModeB.endRadiusVar; 2338 particleModeB.rotatePerSecond = locModeB.rotatePerSecond; 2339 particleModeB.rotatePerSecondVar = locModeB.rotatePerSecondVar; 2340 } 2341 2342 // life span 2343 retParticle._life = this._life; 2344 retParticle._lifeVar = this._lifeVar; 2345 2346 // emission Rate 2347 retParticle._emissionRate = this._emissionRate; 2348 2349 //don't get the internal texture if a batchNode is used 2350 if (!this._batchNode) { 2351 // Set a compatible default for the alpha transfer 2352 retParticle._opacityModifyRGB = this._opacityModifyRGB; 2353 2354 // texture 2355 retParticle._texture = this._texture; 2356 } 2357 } 2358 return retParticle; 2359 }, 2360 2361 /** 2362 * <p> Sets a new CCSpriteFrame as particle.</br> 2363 * WARNING: this method is experimental. Use setTextureWithRect instead. 2364 * </p> 2365 * @param {cc.SpriteFrame} spriteFrame 2366 */ 2367 setDisplayFrame:function (spriteFrame) { 2368 cc.Assert(cc._rectEqualToZero(spriteFrame.getOffsetInPixels()), "QuadParticle only supports SpriteFrames with no offsets"); 2369 2370 // update texture before updating texture rect 2371 if (cc.renderContextType === cc.WEBGL) 2372 if (!this._texture || spriteFrame.getTexture()._webTextureObj != this._texture._webTextureObj) 2373 this.setTexture(spriteFrame.getTexture()); 2374 }, 2375 2376 /** 2377 * Sets a new texture with a rect. The rect is in Points. 2378 * @param {cc.Texture2D} texture 2379 * @param {cc.Rect} rect 2380 */ 2381 setTextureWithRect:function (texture, rect) { 2382 var locTexture = this._texture; 2383 if (cc.renderContextType === cc.WEBGL) { 2384 // Only update the texture if is different from the current one 2385 if ((!locTexture || texture._webTextureObj != locTexture._webTextureObj) && (locTexture != texture)) { 2386 this._texture = texture; 2387 this._updateBlendFunc(); 2388 } 2389 } else { 2390 if ((!locTexture || texture != locTexture) && (locTexture != texture)) { 2391 this._texture = texture; 2392 this._updateBlendFunc(); 2393 } 2394 } 2395 2396 this._pointRect = rect; 2397 this.initTexCoordsWithRect(rect); 2398 }, 2399 2400 /** 2401 * draw particle 2402 * @param {CanvasRenderingContext2D} ctx CanvasContext 2403 * @override 2404 */ 2405 draw:function (ctx) { 2406 cc.Assert(!this._batchNode, "draw should not be called when added to a particleBatchNode"); 2407 if(!this._textureLoaded) 2408 return; 2409 2410 if (cc.renderContextType === cc.CANVAS) 2411 this._drawForCanvas(ctx); 2412 else 2413 this._drawForWebGL(ctx); 2414 2415 cc.g_NumberOfDraws++; 2416 }, 2417 2418 _drawForCanvas:function (ctx) { 2419 var context = ctx || cc.renderContext; 2420 context.save(); 2421 if (this.isBlendAdditive()) 2422 context.globalCompositeOperation = 'lighter'; 2423 else 2424 context.globalCompositeOperation = 'source-over'; 2425 2426 for (var i = 0; i < this._particleCount; i++) { 2427 var particle = this._particles[i]; 2428 var lpx = (0 | (particle.size * 0.5)); 2429 2430 if (this._drawMode == cc.PARTICLE_TEXTURE_MODE) { 2431 2432 var element = this._texture.getHtmlElementObj(); 2433 2434 // Delay drawing until the texture is fully loaded by the browser 2435 if (!element.width || !element.height) 2436 continue; 2437 2438 context.save(); 2439 context.globalAlpha = particle.color.a; 2440 context.translate((0 | particle.drawPos.x), -(0 | particle.drawPos.y)); 2441 2442 var size = Math.floor(particle.size / 4) * 4; 2443 var w = this._pointRect.width; 2444 var h = this._pointRect.height; 2445 2446 context.scale( 2447 Math.max((1 / w) * size, 0.000001), 2448 Math.max((1 / h) * size, 0.000001) 2449 ); 2450 2451 2452 if (particle.rotation) 2453 context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation)); 2454 2455 context.translate(-(0 | (w / 2)), -(0 | (h / 2))); 2456 if (particle.isChangeColor) { 2457 2458 var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(element); 2459 if (cacheTextureForColor) { 2460 // Create another cache for the tinted version 2461 // This speeds up things by a fair bit 2462 if (!cacheTextureForColor.tintCache) { 2463 cacheTextureForColor.tintCache = document.createElement('canvas'); 2464 cacheTextureForColor.tintCache.width = element.width; 2465 cacheTextureForColor.tintCache.height = element.height; 2466 } 2467 cc.generateTintImage(element, cacheTextureForColor, particle.color, this._pointRect, cacheTextureForColor.tintCache); 2468 element = cacheTextureForColor.tintCache; 2469 } 2470 } 2471 2472 context.drawImage(element, 0, 0); 2473 context.restore(); 2474 2475 } else { 2476 context.save(); 2477 context.globalAlpha = particle.color.a; 2478 2479 context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y)); 2480 2481 if (this._shapeType == cc.PARTICLE_STAR_SHAPE) { 2482 if (particle.rotation) 2483 context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation)); 2484 cc.drawingUtil.drawStar(context, lpx, particle.color); 2485 } else 2486 cc.drawingUtil.drawColorBall(context, lpx, particle.color); 2487 context.restore(); 2488 } 2489 } 2490 context.restore(); 2491 }, 2492 2493 _drawForWebGL:function (ctx) { 2494 if(!this._texture) 2495 return; 2496 2497 var gl = ctx || cc.renderContext; 2498 2499 this._shaderProgram.use(); 2500 this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); 2501 2502 cc.glBindTexture2D(this._texture); 2503 cc.glBlendFuncForParticle(this._blendFunc.src, this._blendFunc.dst); 2504 2505 //cc.Assert(this._particleIdx == this._particleCount, "Abnormal error in particle quad"); 2506 2507 // 2508 // Using VBO without VAO 2509 // 2510 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSCOLORTEX); 2511 2512 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2513 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); // vertices 2514 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); // colors 2515 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16); // tex coords 2516 2517 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2518 gl.drawElements(gl.TRIANGLES, this._particleIdx * 6, gl.UNSIGNED_SHORT, 0); 2519 }, 2520 2521 /** 2522 * listen the event that coming to foreground on Android 2523 * @param {cc.Class} obj 2524 */ 2525 listenBackToForeground:function (obj) { 2526 if (cc.TEXTURE_ATLAS_USE_VAO) 2527 this._setupVBOandVAO(); 2528 else 2529 this._setupVBO(); 2530 }, 2531 2532 _setupVBOandVAO:function () { 2533 //Not support on WebGL 2534 /*if (cc.renderContextType == cc.CANVAS) { 2535 return; 2536 }*/ 2537 2538 //NOT SUPPORTED 2539 /*glGenVertexArrays(1, this._VAOname); 2540 glBindVertexArray(this._VAOname); 2541 2542 var kQuadSize = sizeof(m_pQuads[0].bl); 2543 2544 glGenBuffers(2, this._buffersVBO[0]); 2545 2546 glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]); 2547 glBufferData(GL_ARRAY_BUFFER, sizeof(this._quads[0]) * this._totalParticles, this._quads, GL_DYNAMIC_DRAW); 2548 2549 // vertices 2550 glEnableVertexAttribArray(kCCVertexAttrib_Position); 2551 glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, vertices)); 2552 2553 // colors 2554 glEnableVertexAttribArray(kCCVertexAttrib_Color); 2555 glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, offsetof(ccV3F_C4B_T2F, colors)); 2556 2557 // tex coords 2558 glEnableVertexAttribArray(kCCVertexAttrib_TexCoords); 2559 glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, texCoords)); 2560 2561 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2562 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW); 2563 2564 glBindVertexArray(0); 2565 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 2566 glBindBuffer(GL_ARRAY_BUFFER, 0); 2567 2568 CHECK_GL_ERROR_DEBUG();*/ 2569 }, 2570 2571 _setupVBO:function () { 2572 if (cc.renderContextType == cc.CANVAS) 2573 return; 2574 2575 var gl = cc.renderContext; 2576 2577 //gl.deleteBuffer(this._buffersVBO[0]); 2578 this._buffersVBO[0] = gl.createBuffer(); 2579 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2580 gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); 2581 2582 this._buffersVBO[1] = gl.createBuffer(); 2583 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2584 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW); 2585 2586 //cc.CHECK_GL_ERROR_DEBUG(); 2587 }, 2588 2589 _allocMemory:function () { 2590 if (cc.renderContextType === cc.CANVAS) 2591 return true; 2592 2593 //cc.Assert((!this._quads && !this._indices), "Memory already allocated"); 2594 cc.Assert(!this._batchNode, "Memory should not be allocated when not using batchNode"); 2595 var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; 2596 var totalParticles = this._totalParticles; 2597 var locQuads = []; 2598 this._indices = new Uint16Array(totalParticles * 6); 2599 var locQuadsArrayBuffer = new ArrayBuffer(quadSize * totalParticles); 2600 2601 for (var i = 0; i < totalParticles; i++) 2602 locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, i * quadSize); 2603 if (!locQuads || !this._indices) { 2604 cc.log("cocos2d: Particle system: not enough memory"); 2605 return false; 2606 } 2607 this._quads = locQuads; 2608 this._quadsArrayBuffer = locQuadsArrayBuffer; 2609 return true; 2610 } 2611 }); 2612 2613 /** 2614 * <p> return the string found by key in dict. <br/> 2615 * This plist files can be create manually or with Particle Designer:<br/> 2616 * http://particledesigner.71squared.com/<br/> 2617 * </p> 2618 * @param {String} plistFile 2619 * @return {cc.ParticleSystem} 2620 */ 2621 cc.ParticleSystem.create = function (plistFile) { 2622 var ret = new cc.ParticleSystem(); 2623 if (!plistFile || typeof(plistFile) === "number") { 2624 var ton = plistFile || 100; 2625 ret.setDrawMode(cc.PARTICLE_TEXTURE_MODE); 2626 ret.initWithTotalParticles(ton); 2627 return ret; 2628 } 2629 2630 if (ret && ret.initWithFile(plistFile)) 2631 return ret; 2632 return null; 2633 }; 2634 2635 /** 2636 * create a system with a fixed number of particles 2637 * @param {Number} number_of_particles 2638 * @return {cc.ParticleSystem} 2639 */ 2640 cc.ParticleSystem.createWithTotalParticles = function (number_of_particles) { 2641 //emitter.initWithTotalParticles(number_of_particles); 2642 var particle = new cc.ParticleSystem(); 2643 if (particle && particle.initWithTotalParticles(number_of_particles)) 2644 return particle; 2645 return null; 2646 }; 2647 2648 // Different modes 2649 /** 2650 * Mode A:Gravity + Tangential Accel + Radial Accel 2651 * @Class 2652 * @Construct 2653 * @param {cc.Point} [gravity=] Gravity value. 2654 * @param {Number} [speed=0] speed of each particle. 2655 * @param {Number} [speedVar=0] speed variance of each particle. 2656 * @param {Number} [tangentialAccel=0] tangential acceleration of each particle. 2657 * @param {Number} [tangentialAccelVar=0] tangential acceleration variance of each particle. 2658 * @param {Number} [radialAccel=0] radial acceleration of each particle. 2659 * @param {Number} [radialAccelVar=0] radial acceleration variance of each particle. 2660 * @param {boolean} [rotationIsDir=false] 2661 */ 2662 cc.ParticleSystem.ModeA = function (gravity, speed, speedVar, tangentialAccel, tangentialAccelVar, radialAccel, radialAccelVar, rotationIsDir) { 2663 /** Gravity value. Only available in 'Gravity' mode. */ 2664 this.gravity = gravity ? gravity : cc.PointZero(); 2665 /** speed of each particle. Only available in 'Gravity' mode. */ 2666 this.speed = speed || 0; 2667 /** speed variance of each particle. Only available in 'Gravity' mode. */ 2668 this.speedVar = speedVar || 0; 2669 /** tangential acceleration of each particle. Only available in 'Gravity' mode. */ 2670 this.tangentialAccel = tangentialAccel || 0; 2671 /** tangential acceleration variance of each particle. Only available in 'Gravity' mode. */ 2672 this.tangentialAccelVar = tangentialAccelVar || 0; 2673 /** radial acceleration of each particle. Only available in 'Gravity' mode. */ 2674 this.radialAccel = radialAccel || 0; 2675 /** radial acceleration variance of each particle. Only available in 'Gravity' mode. */ 2676 this.radialAccelVar = radialAccelVar || 0; 2677 /** set the rotation of each particle to its direction Only available in 'Gravity' mode. */ 2678 this.rotationIsDir = rotationIsDir || false; 2679 }; 2680 2681 /** 2682 * Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) 2683 * @Class 2684 * @Construct 2685 * @param {Number} startRadius The starting radius of the particles. 2686 * @param {Number} startRadiusVar The starting radius variance of the particles. 2687 * @param {Number} endRadius The ending radius of the particles. 2688 * @param {Number} endRadiusVar The ending radius variance of the particles. 2689 * @param {Number} rotatePerSecond Number of degress to rotate a particle around the source pos per second. 2690 * @param {Number} rotatePerSecondVar Variance in degrees for rotatePerSecond. 2691 */ 2692 cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endRadiusVar, rotatePerSecond, rotatePerSecondVar) { 2693 /** The starting radius of the particles. Only available in 'Radius' mode. */ 2694 this.startRadius = startRadius || 0; 2695 /** The starting radius variance of the particles. Only available in 'Radius' mode. */ 2696 this.startRadiusVar = startRadiusVar || 0; 2697 /** The ending radius of the particles. Only available in 'Radius' mode. */ 2698 this.endRadius = endRadius || 0; 2699 /** The ending radius variance of the particles. Only available in 'Radius' mode. */ 2700 this.endRadiusVar = endRadiusVar || 0; 2701 /** Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. */ 2702 this.rotatePerSecond = rotatePerSecond || 0; 2703 /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */ 2704 this.rotatePerSecondVar = rotatePerSecondVar || 0; 2705 }; 2706