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 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 730 cc.log("cc.ParticleBatchNode.getGravity() : Particle Mode should be Gravity"); 731 var locGravity = this.modeA.gravity; 732 return cc.p(locGravity.x, locGravity.y); 733 }, 734 735 /** 736 * Gravity of emitter setter 737 * @param {cc.Point} gravity 738 */ 739 setGravity:function (gravity) { 740 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 741 cc.log("cc.ParticleBatchNode.setGravity() : Particle Mode should be Gravity"); 742 this.modeA.gravity = gravity; 743 }, 744 745 /** 746 * Return Speed of each particle 747 * @return {Number} 748 */ 749 getSpeed:function () { 750 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 751 cc.log("cc.ParticleBatchNode.getSpeed() : Particle Mode should be Gravity"); 752 return this.modeA.speed; 753 }, 754 755 /** 756 * Speed of each particle setter 757 * @param {Number} speed 758 */ 759 setSpeed:function (speed) { 760 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 761 cc.log("cc.ParticleBatchNode.setSpeed() : Particle Mode should be Gravity"); 762 this.modeA.speed = speed; 763 }, 764 765 /** 766 * return speed variance of each particle. Only available in 'Gravity' mode. 767 * @return {Number} 768 */ 769 getSpeedVar:function () { 770 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 771 cc.log("cc.ParticleBatchNode.getSpeedVar() : Particle Mode should be Gravity"); 772 return this.modeA.speedVar; 773 }, 774 775 /** 776 * speed variance of each particle setter. Only available in 'Gravity' mode. 777 * @param {Number} speedVar 778 */ 779 setSpeedVar:function (speedVar) { 780 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 781 cc.log("cc.ParticleBatchNode.setSpeedVar() : Particle Mode should be Gravity"); 782 this.modeA.speedVar = speedVar; 783 }, 784 785 /** 786 * Return tangential acceleration of each particle. Only available in 'Gravity' mode. 787 * @return {Number} 788 */ 789 getTangentialAccel:function () { 790 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 791 cc.log("cc.ParticleBatchNode.getTangentialAccel() : Particle Mode should be Gravity"); 792 return this.modeA.tangentialAccel; 793 }, 794 795 /** 796 * Tangential acceleration of each particle setter. Only available in 'Gravity' mode. 797 * @param {Number} tangentialAccel 798 */ 799 setTangentialAccel:function (tangentialAccel) { 800 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 801 cc.log("cc.ParticleBatchNode.setTangentialAccel() : Particle Mode should be Gravity"); 802 this.modeA.tangentialAccel = tangentialAccel; 803 }, 804 805 /** 806 * Return tangential acceleration variance of each particle. Only available in 'Gravity' mode. 807 * @return {Number} 808 */ 809 getTangentialAccelVar:function () { 810 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 811 cc.log("cc.ParticleBatchNode.getTangentialAccelVar() : Particle Mode should be Gravity"); 812 return this.modeA.tangentialAccelVar; 813 }, 814 815 /** 816 * tangential acceleration variance of each particle setter. Only available in 'Gravity' mode. 817 * @param {Number} tangentialAccelVar 818 */ 819 setTangentialAccelVar:function (tangentialAccelVar) { 820 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 821 cc.log("cc.ParticleBatchNode.setTangentialAccelVar() : Particle Mode should be Gravity"); 822 this.modeA.tangentialAccelVar = tangentialAccelVar; 823 }, 824 825 /** 826 * Return radial acceleration of each particle. Only available in 'Gravity' mode. 827 * @return {Number} 828 */ 829 getRadialAccel:function () { 830 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 831 cc.log("cc.ParticleBatchNode.getRadialAccel() : Particle Mode should be Gravity"); 832 return this.modeA.radialAccel; 833 }, 834 835 /** 836 * radial acceleration of each particle setter. Only available in 'Gravity' mode. 837 * @param {Number} radialAccel 838 */ 839 setRadialAccel:function (radialAccel) { 840 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 841 cc.log("cc.ParticleBatchNode.setRadialAccel() : Particle Mode should be Gravity"); 842 this.modeA.radialAccel = radialAccel; 843 }, 844 845 /** 846 * Return radial acceleration variance of each particle. Only available in 'Gravity' mode. 847 * @return {Number} 848 */ 849 getRadialAccelVar:function () { 850 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 851 cc.log("cc.ParticleBatchNode.getRadialAccelVar() : Particle Mode should be Gravity"); 852 return this.modeA.radialAccelVar; 853 }, 854 855 /** 856 * radial acceleration variance of each particle setter. Only available in 'Gravity' mode. 857 * @param {Number} radialAccelVar 858 */ 859 setRadialAccelVar:function (radialAccelVar) { 860 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 861 cc.log("cc.ParticleBatchNode.setRadialAccelVar() : Particle Mode should be Gravity"); 862 this.modeA.radialAccelVar = radialAccelVar; 863 }, 864 865 /** 866 * get the rotation of each particle to its direction Only available in 'Gravity' mode. 867 * @returns {boolean} 868 */ 869 getRotationIsDir: function(){ 870 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 871 cc.log("cc.ParticleBatchNode.getRotationIsDir() : Particle Mode should be Gravity"); 872 return this.modeA.rotationIsDir; 873 }, 874 875 /** 876 * set the rotation of each particle to its direction Only available in 'Gravity' mode. 877 * @param {boolean} t 878 */ 879 setRotationIsDir: function(t){ 880 if(this._emitterMode !== cc.PARTICLE_MODE_GRAVITY) 881 cc.log("cc.ParticleBatchNode.setRotationIsDir() : Particle Mode should be Gravity"); 882 this.modeA.rotationIsDir = t; 883 }, 884 885 // mode B 886 /** 887 * Return starting radius of the particles. Only available in 'Radius' mode. 888 * @return {Number} 889 */ 890 getStartRadius:function () { 891 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 892 cc.log("cc.ParticleBatchNode.getStartRadius() : Particle Mode should be Radius"); 893 return this.modeB.startRadius; 894 }, 895 896 /** 897 * starting radius of the particles setter. Only available in 'Radius' mode. 898 * @param {Number} startRadius 899 */ 900 setStartRadius:function (startRadius) { 901 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 902 cc.log("cc.ParticleBatchNode.setStartRadius() : Particle Mode should be Radius"); 903 this.modeB.startRadius = startRadius; 904 }, 905 906 /** 907 * Return starting radius variance of the particles. Only available in 'Radius' mode. 908 * @return {Number} 909 */ 910 getStartRadiusVar:function () { 911 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 912 cc.log("cc.ParticleBatchNode.getStartRadiusVar() : Particle Mode should be Radius"); 913 return this.modeB.startRadiusVar; 914 }, 915 916 /** 917 * starting radius variance of the particles setter. Only available in 'Radius' mode. 918 * @param {Number} startRadiusVar 919 */ 920 setStartRadiusVar:function (startRadiusVar) { 921 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 922 cc.log("cc.ParticleBatchNode.setStartRadiusVar() : Particle Mode should be Radius"); 923 this.modeB.startRadiusVar = startRadiusVar; 924 }, 925 926 /** 927 * Return ending radius of the particles. Only available in 'Radius' mode. 928 * @return {Number} 929 */ 930 getEndRadius:function () { 931 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 932 cc.log("cc.ParticleBatchNode.getEndRadius() : Particle Mode should be Radius"); 933 return this.modeB.endRadius; 934 }, 935 936 /** 937 * ending radius of the particles setter. Only available in 'Radius' mode. 938 * @param {Number} endRadius 939 */ 940 setEndRadius:function (endRadius) { 941 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 942 cc.log("cc.ParticleBatchNode.setEndRadius() : Particle Mode should be Radius"); 943 this.modeB.endRadius = endRadius; 944 }, 945 946 /** 947 * Return ending radius variance of the particles. Only available in 'Radius' mode. 948 * @return {Number} 949 */ 950 getEndRadiusVar:function () { 951 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 952 cc.log("cc.ParticleBatchNode.getEndRadiusVar() : Particle Mode should be Radius"); 953 return this.modeB.endRadiusVar; 954 }, 955 956 /** 957 * ending radius variance of the particles setter. Only available in 'Radius' mode. 958 * @param endRadiusVar 959 */ 960 setEndRadiusVar:function (endRadiusVar) { 961 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 962 cc.log("cc.ParticleBatchNode.setEndRadiusVar() : Particle Mode should be Radius"); 963 this.modeB.endRadiusVar = endRadiusVar; 964 }, 965 966 /** 967 * get Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. 968 * @return {Number} 969 */ 970 getRotatePerSecond:function () { 971 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 972 cc.log("cc.ParticleBatchNode.getRotatePerSecond() : Particle Mode should be Radius"); 973 return this.modeB.rotatePerSecond; 974 }, 975 976 /** 977 * set Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. 978 * @param {Number} degrees 979 */ 980 setRotatePerSecond:function (degrees) { 981 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 982 cc.log("cc.ParticleBatchNode.setRotatePerSecond() : Particle Mode should be Radius"); 983 this.modeB.rotatePerSecond = degrees; 984 }, 985 986 /** 987 * Return Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. 988 * @return {Number} 989 */ 990 getRotatePerSecondVar:function () { 991 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 992 cc.log("cc.ParticleBatchNode.getRotatePerSecondVar() : Particle Mode should be Radius"); 993 return this.modeB.rotatePerSecondVar; 994 }, 995 996 /** 997 * Variance in degrees for rotatePerSecond setter. Only available in 'Radius' mode. 998 * @param degrees 999 */ 1000 setRotatePerSecondVar:function (degrees) { 1001 if(this._emitterMode !== cc.PARTICLE_MODE_RADIUS) 1002 cc.log("cc.ParticleBatchNode.setRotatePerSecondVar() : Particle Mode should be Radius"); 1003 this.modeB.rotatePerSecondVar = degrees; 1004 }, 1005 ////////////////////////////////////////////////////////////////////////// 1006 1007 //don't use a transform matrix, this is faster 1008 setScale:function (scale, scaleY) { 1009 this._transformSystemDirty = true; 1010 cc.Node.prototype.setScale.call(this, scale, scaleY); 1011 }, 1012 1013 setRotation:function (newRotation) { 1014 this._transformSystemDirty = true; 1015 cc.Node.prototype.setRotation.call(this, newRotation); 1016 }, 1017 1018 setScaleX:function (newScaleX) { 1019 this._transformSystemDirty = true; 1020 cc.Node.prototype.setScaleX.call(this, newScaleX); 1021 }, 1022 1023 setScaleY:function (newScaleY) { 1024 this._transformSystemDirty = true; 1025 cc.Node.prototype.setScaleY.call(this, newScaleY); 1026 }, 1027 1028 /** 1029 * get start size in pixels of each particle 1030 * @return {Number} 1031 */ 1032 getStartSize:function () { 1033 return this._startSize; 1034 }, 1035 1036 /** 1037 * set start size in pixels of each particle 1038 * @param {Number} startSize 1039 */ 1040 setStartSize:function (startSize) { 1041 this._startSize = startSize; 1042 }, 1043 1044 /** 1045 * get size variance in pixels of each particle 1046 * @return {Number} 1047 */ 1048 getStartSizeVar:function () { 1049 return this._startSizeVar; 1050 }, 1051 1052 /** 1053 * set size variance in pixels of each particle 1054 * @param {Number} startSizeVar 1055 */ 1056 setStartSizeVar:function (startSizeVar) { 1057 this._startSizeVar = startSizeVar; 1058 }, 1059 1060 /** 1061 * get end size in pixels of each particle 1062 * @return {Number} 1063 */ 1064 getEndSize:function () { 1065 return this._endSize; 1066 }, 1067 1068 /** 1069 * set end size in pixels of each particle 1070 * @param endSize 1071 */ 1072 setEndSize:function (endSize) { 1073 this._endSize = endSize; 1074 }, 1075 1076 /** 1077 * get end size variance in pixels of each particle 1078 * @return {Number} 1079 */ 1080 getEndSizeVar:function () { 1081 return this._endSizeVar; 1082 }, 1083 1084 /** 1085 * set end size variance in pixels of each particle 1086 * @param {Number} endSizeVar 1087 */ 1088 setEndSizeVar:function (endSizeVar) { 1089 this._endSizeVar = endSizeVar; 1090 }, 1091 1092 /** 1093 * set start color of each particle 1094 * @return {cc.Color4F} 1095 */ 1096 getStartColor:function () { 1097 return this._startColor; 1098 }, 1099 1100 /** 1101 * get start color of each particle 1102 * @param {cc.Color4F} startColor 1103 */ 1104 setStartColor:function (startColor) { 1105 if (startColor instanceof cc.Color3B) 1106 startColor = cc.c4FFromccc3B(startColor); 1107 this._startColor = startColor; 1108 }, 1109 1110 /** 1111 * get start color variance of each particle 1112 * @return {cc.Color4F} 1113 */ 1114 getStartColorVar:function () { 1115 return this._startColorVar; 1116 }, 1117 1118 /** 1119 * set start color variance of each particle 1120 * @param {cc.Color4F} startColorVar 1121 */ 1122 setStartColorVar:function (startColorVar) { 1123 if (startColorVar instanceof cc.Color3B) 1124 startColorVar = cc.c4FFromccc3B(startColorVar); 1125 this._startColorVar = startColorVar; 1126 }, 1127 1128 /** 1129 * get end color and end color variation of each particle 1130 * @return {cc.Color4F} 1131 */ 1132 getEndColor:function () { 1133 return this._endColor; 1134 }, 1135 1136 /** 1137 * set end color and end color variation of each particle 1138 * @param {cc.Color4F} endColor 1139 */ 1140 setEndColor:function (endColor) { 1141 if (endColor instanceof cc.Color3B) 1142 endColor = cc.c4FFromccc3B(endColor); 1143 this._endColor = endColor; 1144 }, 1145 1146 /** 1147 * get end color variance of each particle 1148 * @return {cc.Color4F} 1149 */ 1150 getEndColorVar:function () { 1151 return this._endColorVar; 1152 }, 1153 1154 /** 1155 * set end color variance of each particle 1156 * @param {cc.Color4F} endColorVar 1157 */ 1158 setEndColorVar:function (endColorVar) { 1159 if (endColorVar instanceof cc.Color3B) 1160 endColorVar = cc.c4FFromccc3B(endColorVar); 1161 this._endColorVar = endColorVar; 1162 }, 1163 1164 /** 1165 * get initial angle of each particle 1166 * @return {Number} 1167 */ 1168 getStartSpin:function () { 1169 return this._startSpin; 1170 }, 1171 1172 /** 1173 * set initial angle of each particle 1174 * @param {Number} startSpin 1175 */ 1176 setStartSpin:function (startSpin) { 1177 this._startSpin = startSpin; 1178 }, 1179 1180 /** 1181 * get initial angle variance of each particle 1182 * @return {Number} 1183 */ 1184 getStartSpinVar:function () { 1185 return this._startSpinVar; 1186 }, 1187 1188 /** 1189 * set initial angle variance of each particle 1190 * @param {Number} startSpinVar 1191 */ 1192 setStartSpinVar:function (startSpinVar) { 1193 this._startSpinVar = startSpinVar; 1194 }, 1195 1196 /** 1197 * get end angle of each particle 1198 * @return {Number} 1199 */ 1200 getEndSpin:function () { 1201 return this._endSpin; 1202 }, 1203 1204 /** 1205 * set end angle of each particle 1206 * @param {Number} endSpin 1207 */ 1208 setEndSpin:function (endSpin) { 1209 this._endSpin = endSpin; 1210 }, 1211 1212 /** 1213 * get end angle variance of each particle 1214 * @return {Number} 1215 */ 1216 getEndSpinVar:function () { 1217 return this._endSpinVar; 1218 }, 1219 1220 /** 1221 * set end angle variance of each particle 1222 * @param {Number} endSpinVar 1223 */ 1224 setEndSpinVar:function (endSpinVar) { 1225 this._endSpinVar = endSpinVar; 1226 }, 1227 1228 /** 1229 * get emission rate of the particles 1230 * @return {Number} 1231 */ 1232 getEmissionRate:function () { 1233 return this._emissionRate; 1234 }, 1235 1236 /** 1237 * set emission rate of the particles 1238 * @param {Number} emissionRate 1239 */ 1240 setEmissionRate:function (emissionRate) { 1241 this._emissionRate = emissionRate; 1242 }, 1243 1244 /** 1245 * get maximum particles of the system 1246 * @return {Number} 1247 */ 1248 getTotalParticles:function () { 1249 return this._totalParticles; 1250 }, 1251 1252 /** 1253 * set maximum particles of the system 1254 * @param {Number} tp totalParticles 1255 */ 1256 setTotalParticles:function (tp) { 1257 //cc.Assert(tp <= this._allocatedParticles, "Particle: resizing particle array only supported for quads"); 1258 if (cc.renderContextType === cc.CANVAS){ 1259 this._totalParticles = (tp < 200) ? tp : 200; 1260 return; 1261 } 1262 1263 // If we are setting the total numer of particles to a number higher 1264 // than what is allocated, we need to allocate new arrays 1265 if (tp > this._allocatedParticles) { 1266 var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; 1267 // Allocate new memory 1268 this._indices = new Uint16Array(tp * 6); 1269 var locQuadsArrayBuffer = new ArrayBuffer(tp * quadSize); 1270 //TODO need fix 1271 // Assign pointers 1272 var locParticles = this._particles; 1273 locParticles.length = 0; 1274 var locQuads = this._quads; 1275 locQuads.length = 0; 1276 for (var j = 0; j < tp; j++) { 1277 locParticles[j] = new cc.Particle(); 1278 locQuads[j] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, j * quadSize); 1279 } 1280 this._allocatedParticles = tp; 1281 this._totalParticles = tp; 1282 1283 // Init particles 1284 if (this._batchNode) { 1285 for (var i = 0; i < tp; i++) 1286 locParticles[i].atlasIndex = i; 1287 } 1288 1289 this._quadsArrayBuffer = locQuadsArrayBuffer; 1290 1291 this.initIndices(); 1292 //if (cc.TEXTURE_ATLAS_USE_VAO) 1293 // this._setupVBOandVAO(); 1294 //else 1295 this._setupVBO(); 1296 1297 //set the texture coord 1298 if(this._texture){ 1299 var size = this._texture.getContentSize(); 1300 this.initTexCoordsWithRect(cc.rect(0, 0, size.width, size.height)); 1301 } 1302 } else 1303 this._totalParticles = tp; 1304 this.resetSystem(); 1305 }, 1306 1307 /** 1308 * get Texture of Particle System 1309 * @return {cc.Texture2D} 1310 */ 1311 getTexture:function () { 1312 return this._texture; 1313 }, 1314 1315 /** 1316 * set Texture of Particle System 1317 * @param {cc.Texture2D } texture 1318 */ 1319 setTexture:function (texture) { 1320 if(texture.isLoaded()){ 1321 var size = texture.getContentSize(); 1322 this.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height)); 1323 } else { 1324 this._textureLoaded = false; 1325 texture.addLoadedEventListener(function(sender){ 1326 this._textureLoaded = true; 1327 var size = sender.getContentSize(); 1328 this.setTextureWithRect(sender, cc.rect(0, 0, size.width, size.height)); 1329 }, this); 1330 } 1331 }, 1332 1333 /** conforms to CocosNodeTexture protocol */ 1334 /** 1335 * get BlendFunc of Particle System 1336 * @return {cc.BlendFunc} 1337 */ 1338 getBlendFunc:function () { 1339 return this._blendFunc; 1340 }, 1341 1342 /** 1343 * set BlendFunc of Particle System 1344 * @param {Number} src 1345 * @param {Number} dst 1346 */ 1347 setBlendFunc:function (src, dst) { 1348 if (arguments.length == 1) { 1349 if (this._blendFunc != src) { 1350 this._blendFunc = src; 1351 this._updateBlendFunc(); 1352 } 1353 } else { 1354 if (this._blendFunc.src != src || this._blendFunc.dst != dst) { 1355 this._blendFunc = {src:src, dst:dst}; 1356 this._updateBlendFunc(); 1357 } 1358 } 1359 }, 1360 1361 /** 1362 * does the alpha value modify color getter 1363 * @return {Boolean} 1364 */ 1365 getOpacityModifyRGB:function () { 1366 return this._opacityModifyRGB; 1367 }, 1368 1369 /** 1370 * does the alpha value modify color setter 1371 * @param newValue 1372 */ 1373 setOpacityModifyRGB:function (newValue) { 1374 this._opacityModifyRGB = newValue; 1375 }, 1376 1377 /** 1378 * <p>whether or not the particles are using blend additive.<br/> 1379 * If enabled, the following blending function will be used.<br/> 1380 * </p> 1381 * @return {Boolean} 1382 * @example 1383 * source blend function = GL_SRC_ALPHA; 1384 * dest blend function = GL_ONE; 1385 */ 1386 isBlendAdditive:function () { 1387 return (( this._blendFunc.src == gl.SRC_ALPHA && this._blendFunc.dst == gl.ONE) || (this._blendFunc.src == gl.ONE && this._blendFunc.dst == gl.ONE)); 1388 }, 1389 1390 /** 1391 * <p>whether or not the particles are using blend additive.<br/> 1392 * If enabled, the following blending function will be used.<br/> 1393 * </p> 1394 * @param {Boolean} isBlendAdditive 1395 */ 1396 setBlendAdditive:function (isBlendAdditive) { 1397 var locBlendFunc = this._blendFunc; 1398 if (isBlendAdditive) { 1399 locBlendFunc.src = gl.SRC_ALPHA; 1400 locBlendFunc.dst = gl.ONE; 1401 } else { 1402 if (cc.renderContextType === cc.WEBGL) { 1403 if (this._texture && !this._texture.hasPremultipliedAlpha()) { 1404 locBlendFunc.src = gl.SRC_ALPHA; 1405 locBlendFunc.dst = gl.ONE_MINUS_SRC_ALPHA; 1406 } else { 1407 locBlendFunc.src = cc.BLEND_SRC; 1408 locBlendFunc.dst = cc.BLEND_DST; 1409 } 1410 } else { 1411 locBlendFunc.src = cc.BLEND_SRC; 1412 locBlendFunc.dst = cc.BLEND_DST; 1413 } 1414 } 1415 }, 1416 1417 /** 1418 * get particles movement type: Free or Grouped 1419 * @return {Number} 1420 */ 1421 getPositionType:function () { 1422 return this._positionType; 1423 }, 1424 1425 /** 1426 * set particles movement type: Free or Grouped 1427 * @param {Number} positionType 1428 */ 1429 setPositionType:function (positionType) { 1430 this._positionType = positionType; 1431 }, 1432 1433 /** 1434 * <p> return whether or not the node will be auto-removed when it has no particles left.<br/> 1435 * By default it is false.<br/> 1436 * </p> 1437 * @return {Boolean} 1438 */ 1439 isAutoRemoveOnFinish:function () { 1440 return this._isAutoRemoveOnFinish; 1441 }, 1442 1443 /** 1444 * <p> set whether or not the node will be auto-removed when it has no particles left.<br/> 1445 * By default it is false.<br/> 1446 * </p> 1447 * @param {Boolean} isAutoRemoveOnFinish 1448 */ 1449 setAutoRemoveOnFinish:function (isAutoRemoveOnFinish) { 1450 this._isAutoRemoveOnFinish = isAutoRemoveOnFinish; 1451 }, 1452 1453 /** 1454 * return kind of emitter modes 1455 * @return {Number} 1456 */ 1457 getEmitterMode:function () { 1458 return this._emitterMode; 1459 }, 1460 1461 /** 1462 * <p>Switch between different kind of emitter modes:<br/> 1463 * - CCPARTICLE_MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration<br/> 1464 * - CCPARTICLE_MODE_RADIUS: uses radius movement + rotation <br/> 1465 * </p> 1466 * @param {Number} emitterMode 1467 */ 1468 setEmitterMode:function (emitterMode) { 1469 this._emitterMode = emitterMode; 1470 }, 1471 1472 /** 1473 * initializes a cc.ParticleSystem 1474 */ 1475 init:function () { 1476 return this.initWithTotalParticles(150); 1477 }, 1478 1479 /** 1480 * <p> 1481 * initializes a CCParticleSystem from a plist file. <br/> 1482 * This plist files can be creted manually or with Particle Designer:<br/> 1483 * http://particledesigner.71squared.com/ 1484 * </p> 1485 * @param {String} plistFile 1486 * @return {boolean} 1487 */ 1488 initWithFile:function (plistFile) { 1489 this._plistFile = plistFile; 1490 var fileUtils = cc.FileUtils.getInstance(); 1491 var fullPath = fileUtils.fullPathForFilename(plistFile); 1492 1493 var dict = fileUtils.dictionaryWithContentsOfFileThreadSafe(fullPath); 1494 if(!dict){ 1495 cc.log("cc.ParticleSystem.initWithFile(): Particles: file not found"); 1496 return false; 1497 } 1498 1499 // XXX compute path from a path, should define a function somewhere to do it 1500 return this.initWithDictionary(dict, ""); 1501 }, 1502 1503 /** 1504 * return bounding box of particle system in world space 1505 * @return {cc.Rect} 1506 */ 1507 getBoundingBoxToWorld:function () { 1508 return cc.rect(0, 0, cc.canvas.width, cc.canvas.height); 1509 }, 1510 1511 /** 1512 * initializes a particle system from a NSDictionary and the path from where to load the png 1513 * @param {object} dictionary 1514 * @param {String} dirname 1515 * @return {Boolean} 1516 */ 1517 initWithDictionary:function (dictionary, dirname) { 1518 var ret = false; 1519 var buffer = null; 1520 var image = null; 1521 var locValueForKey = this._valueForKey; 1522 1523 var maxParticles = parseInt(locValueForKey("maxParticles", dictionary)); 1524 // self, not super 1525 if (this.initWithTotalParticles(maxParticles)) { 1526 // angle 1527 this._angle = parseFloat(locValueForKey("angle", dictionary)); 1528 this._angleVar = parseFloat(locValueForKey("angleVariance", dictionary)); 1529 1530 // duration 1531 this._duration = parseFloat(locValueForKey("duration", dictionary)); 1532 1533 // blend function 1534 this._blendFunc.src = parseInt(locValueForKey("blendFuncSource", dictionary)); 1535 this._blendFunc.dst = parseInt(locValueForKey("blendFuncDestination", dictionary)); 1536 1537 // color 1538 var locStartColor = this._startColor; 1539 locStartColor.r = parseFloat(locValueForKey("startColorRed", dictionary)); 1540 locStartColor.g = parseFloat(locValueForKey("startColorGreen", dictionary)); 1541 locStartColor.b = parseFloat(locValueForKey("startColorBlue", dictionary)); 1542 locStartColor.a = parseFloat(locValueForKey("startColorAlpha", dictionary)); 1543 1544 var locStartColorVar = this._startColorVar; 1545 locStartColorVar.r = parseFloat(locValueForKey("startColorVarianceRed", dictionary)); 1546 locStartColorVar.g = parseFloat(locValueForKey("startColorVarianceGreen", dictionary)); 1547 locStartColorVar.b = parseFloat(locValueForKey("startColorVarianceBlue", dictionary)); 1548 locStartColorVar.a = parseFloat(locValueForKey("startColorVarianceAlpha", dictionary)); 1549 1550 var locEndColor = this._endColor; 1551 locEndColor.r = parseFloat(locValueForKey("finishColorRed", dictionary)); 1552 locEndColor.g = parseFloat(locValueForKey("finishColorGreen", dictionary)); 1553 locEndColor.b = parseFloat(locValueForKey("finishColorBlue", dictionary)); 1554 locEndColor.a = parseFloat(locValueForKey("finishColorAlpha", dictionary)); 1555 1556 var locEndColorVar = this._endColorVar; 1557 locEndColorVar.r = parseFloat(locValueForKey("finishColorVarianceRed", dictionary)); 1558 locEndColorVar.g = parseFloat(locValueForKey("finishColorVarianceGreen", dictionary)); 1559 locEndColorVar.b = parseFloat(locValueForKey("finishColorVarianceBlue", dictionary)); 1560 locEndColorVar.a = parseFloat(locValueForKey("finishColorVarianceAlpha", dictionary)); 1561 1562 // particle size 1563 this._startSize = parseFloat(locValueForKey("startParticleSize", dictionary)); 1564 this._startSizeVar = parseFloat(locValueForKey("startParticleSizeVariance", dictionary)); 1565 this._endSize = parseFloat(locValueForKey("finishParticleSize", dictionary)); 1566 this._endSizeVar = parseFloat(locValueForKey("finishParticleSizeVariance", dictionary)); 1567 1568 // position 1569 var x = parseFloat(locValueForKey("sourcePositionx", dictionary)); 1570 var y = parseFloat(locValueForKey("sourcePositiony", dictionary)); 1571 this.setPosition(x, y); 1572 this._posVar.x = parseFloat(locValueForKey("sourcePositionVariancex", dictionary)); 1573 this._posVar.y = parseFloat(locValueForKey("sourcePositionVariancey", dictionary)); 1574 1575 // Spinning 1576 this._startSpin = parseFloat(locValueForKey("rotationStart", dictionary)); 1577 this._startSpinVar = parseFloat(locValueForKey("rotationStartVariance", dictionary)); 1578 this._endSpin = parseFloat(locValueForKey("rotationEnd", dictionary)); 1579 this._endSpinVar = parseFloat(locValueForKey("rotationEndVariance", dictionary)); 1580 1581 this._emitterMode = parseInt(locValueForKey("emitterType", dictionary)); 1582 1583 // Mode A: Gravity + tangential accel + radial accel 1584 if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) { 1585 var locModeA = this.modeA; 1586 // gravity 1587 locModeA.gravity.x = parseFloat(locValueForKey("gravityx", dictionary)); 1588 locModeA.gravity.y = parseFloat(locValueForKey("gravityy", dictionary)); 1589 1590 // speed 1591 locModeA.speed = parseFloat(locValueForKey("speed", dictionary)); 1592 locModeA.speedVar = parseFloat(locValueForKey("speedVariance", dictionary)); 1593 1594 // radial acceleration 1595 var pszTmp = locValueForKey("radialAcceleration", dictionary); 1596 locModeA.radialAccel = (pszTmp) ? parseFloat(pszTmp) : 0; 1597 1598 pszTmp = locValueForKey("radialAccelVariance", dictionary); 1599 locModeA.radialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0; 1600 1601 // tangential acceleration 1602 pszTmp = locValueForKey("tangentialAcceleration", dictionary); 1603 locModeA.tangentialAccel = (pszTmp) ? parseFloat(pszTmp) : 0; 1604 1605 pszTmp = locValueForKey("tangentialAccelVariance", dictionary); 1606 locModeA.tangentialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0; 1607 1608 // rotation is dir 1609 var locRotationIsDir = locValueForKey("rotationIsDir", dictionary).toLowerCase(); 1610 locModeA.rotationIsDir = (locRotationIsDir != null && (locRotationIsDir === "true" || locRotationIsDir === "1")); 1611 } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) { 1612 // or Mode B: radius movement 1613 var locModeB = this.modeB; 1614 locModeB.startRadius = parseFloat(locValueForKey("maxRadius", dictionary)); 1615 locModeB.startRadiusVar = parseFloat(locValueForKey("maxRadiusVariance", dictionary)); 1616 locModeB.endRadius = parseFloat(locValueForKey("minRadius", dictionary)); 1617 locModeB.endRadiusVar = 0; 1618 locModeB.rotatePerSecond = parseFloat(locValueForKey("rotatePerSecond", dictionary)); 1619 locModeB.rotatePerSecondVar = parseFloat(locValueForKey("rotatePerSecondVariance", dictionary)); 1620 } else { 1621 cc.log("cc.ParticleSystem.initWithDictionary(): Invalid emitterType in config file"); 1622 return false; 1623 } 1624 1625 // life span 1626 this._life = parseFloat(locValueForKey("particleLifespan", dictionary)); 1627 this._lifeVar = parseFloat(locValueForKey("particleLifespanVariance", dictionary)); 1628 1629 // emission Rate 1630 this._emissionRate = this._totalParticles / this._life; 1631 1632 //don't get the internal texture if a batchNode is used 1633 if (!this._batchNode) { 1634 // Set a compatible default for the alpha transfer 1635 this._opacityModifyRGB = false; 1636 1637 // texture 1638 // Try to get the texture from the cache 1639 var textureName = locValueForKey("textureFileName", dictionary); 1640 var fileUtils = cc.FileUtils.getInstance(); 1641 var imgPath = fileUtils.fullPathFromRelativeFile(textureName, this._plistFile); 1642 var tex = cc.TextureCache.getInstance().textureForKey(imgPath); 1643 1644 if (tex) { 1645 this.setTexture(tex); 1646 } else { 1647 var textureData = locValueForKey("textureImageData", dictionary); 1648 1649 if (textureData && textureData.length == 0) { 1650 tex = cc.TextureCache.getInstance().addImage(imgPath); 1651 if (!tex) 1652 return false; 1653 this.setTexture(tex); 1654 } else { 1655 buffer = cc.unzipBase64AsArray(textureData, 1); 1656 if (!buffer) { 1657 cc.log("cc.ParticleSystem: error decoding or ungzipping textureImageData"); 1658 return false; 1659 } 1660 1661 var imageFormat = cc.getImageFormatByData(buffer); 1662 1663 if(imageFormat !== cc.FMT_TIFF && imageFormat !== cc.FMT_PNG){ 1664 cc.log("cc.ParticleSystem: unknown image format with Data"); 1665 return false; 1666 } 1667 1668 var canvasObj = document.createElement("canvas"); 1669 if(imageFormat === cc.FMT_PNG){ 1670 var myPngObj = new cc.PNGReader(buffer); 1671 myPngObj.render(canvasObj); 1672 } else { 1673 var myTIFFObj = cc.TIFFReader.getInstance(); 1674 myTIFFObj.parseTIFF(buffer,canvasObj); 1675 } 1676 1677 var imgFullPath = fileUtils.fullPathForFilename(imgPath); 1678 cc.TextureCache.getInstance().cacheImage(imgFullPath, canvasObj); 1679 1680 var addTexture = cc.TextureCache.getInstance().textureForKey(imgPath); 1681 if(!addTexture) 1682 cc.log("cc.ParticleSystem.initWithDictionary() : error loading the texture"); 1683 this.setTexture(addTexture); 1684 } 1685 } 1686 } 1687 ret = true; 1688 } 1689 return ret; 1690 }, 1691 1692 /** 1693 * Initializes a system with a fixed number of particles 1694 * @param {Number} numberOfParticles 1695 * @return {Boolean} 1696 */ 1697 initWithTotalParticles:function (numberOfParticles) { 1698 this._totalParticles = numberOfParticles; 1699 1700 var i, locParticles = this._particles; 1701 locParticles.length = 0; 1702 for(i = 0; i< numberOfParticles; i++){ 1703 locParticles[i] = new cc.Particle(); 1704 } 1705 1706 if (!locParticles) { 1707 cc.log("Particle system: not enough memory"); 1708 return false; 1709 } 1710 this._allocatedParticles = numberOfParticles; 1711 1712 if (this._batchNode) 1713 for (i = 0; i < this._totalParticles; i++) 1714 locParticles[i].atlasIndex = i; 1715 1716 // default, active 1717 this._isActive = true; 1718 1719 // default blend function 1720 this._blendFunc.src = cc.BLEND_SRC; 1721 this._blendFunc.dst = cc.BLEND_DST; 1722 1723 // default movement type; 1724 this._positionType = cc.PARTICLE_TYPE_FREE; 1725 1726 // by default be in mode A: 1727 this._emitterMode = cc.PARTICLE_MODE_GRAVITY; 1728 1729 // default: modulate 1730 // XXX: not used 1731 // colorModulate = YES; 1732 this._isAutoRemoveOnFinish = false; 1733 1734 //for batchNode 1735 this._transformSystemDirty = false; 1736 1737 // udpate after action in run! 1738 this.scheduleUpdateWithPriority(1); 1739 1740 if(cc.renderContextType === cc.WEBGL){ 1741 // allocating data space 1742 if (!this._allocMemory()) 1743 return false; 1744 1745 this.initIndices(); 1746 //if (cc.TEXTURE_ATLAS_USE_VAO) 1747 // this._setupVBOandVAO(); 1748 //else 1749 this._setupVBO(); 1750 1751 this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_TEXTURECOLOR)); 1752 } 1753 1754 return true; 1755 }, 1756 1757 destroyParticleSystem:function () { 1758 this.unscheduleUpdate(); 1759 }, 1760 1761 /** 1762 * Add a particle to the emitter 1763 * @return {Boolean} 1764 */ 1765 addParticle: function () { 1766 if (this.isFull()) 1767 return false; 1768 var particle, particles = this._particles; 1769 if (cc.renderContextType === cc.CANVAS) { 1770 if (this._particleCount < particles.length) { 1771 particle = particles[this._particleCount]; 1772 } else { 1773 particle = new cc.Particle(); 1774 particles.push(particle); 1775 } 1776 } else { 1777 particle = particles[this._particleCount]; 1778 } 1779 this.initParticle(particle); 1780 ++this._particleCount; 1781 return true; 1782 }, 1783 1784 /** 1785 * Initializes a particle 1786 * @param {cc.Particle} particle 1787 */ 1788 initParticle:function (particle) { 1789 var locRandomMinus11 = cc.RANDOM_MINUS1_1; 1790 // timeToLive 1791 // no negative life. prevent division by 0 1792 particle.timeToLive = this._life + this._lifeVar * locRandomMinus11(); 1793 particle.timeToLive = Math.max(0, particle.timeToLive); 1794 1795 // position 1796 particle.pos.x = this._sourcePosition.x + this._posVar.x * locRandomMinus11(); 1797 particle.pos.y = this._sourcePosition.y + this._posVar.y * locRandomMinus11(); 1798 1799 // Color 1800 var start, end; 1801 var locStartColor = this._startColor, locStartColorVar = this._startColorVar; 1802 var locEndColor = this._endColor, locEndColorVar = this._endColorVar; 1803 if (cc.renderContextType === cc.CANVAS) { 1804 start = new cc.Color4F( 1805 cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 1), 1806 cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 1), 1807 cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 1), 1808 cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 1) 1809 ); 1810 end = new cc.Color4F( 1811 cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 1), 1812 cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 1), 1813 cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 1), 1814 cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 1) 1815 ); 1816 } else { 1817 start = { 1818 r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 1), 1819 g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 1), 1820 b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 1), 1821 a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 1) 1822 }; 1823 end = { 1824 r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 1), 1825 g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 1), 1826 b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 1), 1827 a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 1) 1828 }; 1829 } 1830 1831 particle.color = start; 1832 var locParticleDeltaColor = particle.deltaColor, locParticleTimeToLive = particle.timeToLive; 1833 locParticleDeltaColor.r = (end.r - start.r) / locParticleTimeToLive; 1834 locParticleDeltaColor.g = (end.g - start.g) / locParticleTimeToLive; 1835 locParticleDeltaColor.b = (end.b - start.b) / locParticleTimeToLive; 1836 locParticleDeltaColor.a = (end.a - start.a) / locParticleTimeToLive; 1837 1838 // size 1839 var startS = this._startSize + this._startSizeVar * locRandomMinus11(); 1840 startS = Math.max(0, startS); // No negative value 1841 1842 particle.size = startS; 1843 if (this._endSize === cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE) { 1844 particle.deltaSize = 0; 1845 } else { 1846 var endS = this._endSize + this._endSizeVar * locRandomMinus11(); 1847 endS = Math.max(0, endS); // No negative values 1848 particle.deltaSize = (endS - startS) / locParticleTimeToLive; 1849 } 1850 1851 // rotation 1852 var startA = this._startSpin + this._startSpinVar * locRandomMinus11(); 1853 var endA = this._endSpin + this._endSpinVar * locRandomMinus11(); 1854 particle.rotation = startA; 1855 particle.deltaRotation = (endA - startA) / locParticleTimeToLive; 1856 1857 // position 1858 if (this._positionType == cc.PARTICLE_TYPE_FREE) 1859 particle.startPos = this.convertToWorldSpace(this._pointZeroForParticle); 1860 else if (this._positionType == cc.PARTICLE_TYPE_RELATIVE){ 1861 particle.startPos.x = this._position.x; 1862 particle.startPos.y = this._position.y; 1863 } 1864 1865 // direction 1866 var a = cc.DEGREES_TO_RADIANS(this._angle + this._angleVar * locRandomMinus11()); 1867 1868 // Mode Gravity: A 1869 if (this._emitterMode === cc.PARTICLE_MODE_GRAVITY) { 1870 var locModeA = this.modeA, locParticleModeA = particle.modeA; 1871 var s = locModeA.speed + locModeA.speedVar * locRandomMinus11(); 1872 1873 // direction 1874 locParticleModeA.dir.x = Math.cos(a); 1875 locParticleModeA.dir.y = Math.sin(a); 1876 cc.pMultIn(locParticleModeA.dir, s); 1877 1878 // radial accel 1879 locParticleModeA.radialAccel = locModeA.radialAccel + locModeA.radialAccelVar * locRandomMinus11(); 1880 1881 // tangential accel 1882 locParticleModeA.tangentialAccel = locModeA.tangentialAccel + locModeA.tangentialAccelVar * locRandomMinus11(); 1883 1884 // rotation is dir 1885 if(locModeA.rotationIsDir) 1886 particle.rotation = -cc.RADIANS_TO_DEGREES(cc.pToAngle(locParticleModeA.dir)); 1887 } else { 1888 // Mode Radius: B 1889 var locModeB = this.modeB, locParitlceModeB = particle.modeB; 1890 1891 // Set the default diameter of the particle from the source position 1892 var startRadius = locModeB.startRadius + locModeB.startRadiusVar * locRandomMinus11(); 1893 var endRadius = locModeB.endRadius + locModeB.endRadiusVar * locRandomMinus11(); 1894 1895 locParitlceModeB.radius = startRadius; 1896 locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive; 1897 1898 locParitlceModeB.angle = a; 1899 locParitlceModeB.degreesPerSecond = cc.DEGREES_TO_RADIANS(locModeB.rotatePerSecond + locModeB.rotatePerSecondVar * locRandomMinus11()); 1900 } 1901 }, 1902 1903 /** 1904 * stop emitting particles. Running particles will continue to run until they die 1905 */ 1906 stopSystem:function () { 1907 this._isActive = false; 1908 this._elapsed = this._duration; 1909 this._emitCounter = 0; 1910 }, 1911 1912 /** 1913 * Kill all living particles. 1914 */ 1915 resetSystem:function () { 1916 this._isActive = true; 1917 this._elapsed = 0; 1918 var locParticles = this._particles; 1919 for (this._particleIdx = 0; this._particleIdx < this._particleCount; ++this._particleIdx) 1920 locParticles[this._particleIdx].timeToLive = 0 ; 1921 }, 1922 1923 /** 1924 * whether or not the system is full 1925 * @return {Boolean} 1926 */ 1927 isFull:function () { 1928 return (this._particleCount >= this._totalParticles); 1929 }, 1930 1931 /** 1932 * should be overridden by subclasses 1933 * @param {cc.Particle} particle 1934 * @param {cc.Point} newPosition 1935 */ 1936 updateQuadWithParticle:function (particle, newPosition) { 1937 var quad = null; 1938 if (this._batchNode) { 1939 var batchQuads = this._batchNode.getTextureAtlas().getQuads(); 1940 quad = batchQuads[this._atlasIndex + particle.atlasIndex]; 1941 this._batchNode.getTextureAtlas()._dirty = true; 1942 } else 1943 quad = this._quads[this._particleIdx]; 1944 1945 var r, g, b, a; 1946 if(this._opacityModifyRGB){ 1947 r = 0 | (particle.color.r * particle.color.a * 255); 1948 g = 0 | (particle.color.g * particle.color.a * 255); 1949 b = 0 | (particle.color.b * particle.color.a * 255); 1950 a = 0 | (particle.color.a * 255); 1951 }else{ 1952 r = 0 | (particle.color.r * 255); 1953 g = 0 | (particle.color.g * 255); 1954 b = 0 | (particle.color.b * 255); 1955 a = 0 | (particle.color.a * 255); 1956 } 1957 1958 var locColors = quad.bl.colors; 1959 locColors.r = r; 1960 locColors.g = g; 1961 locColors.b = b; 1962 locColors.a = a; 1963 1964 locColors = quad.br.colors; 1965 locColors.r = r; 1966 locColors.g = g; 1967 locColors.b = b; 1968 locColors.a = a; 1969 1970 locColors = quad.tl.colors; 1971 locColors.r = r; 1972 locColors.g = g; 1973 locColors.b = b; 1974 locColors.a = a; 1975 1976 locColors = quad.tr.colors; 1977 locColors.r = r; 1978 locColors.g = g; 1979 locColors.b = b; 1980 locColors.a = a; 1981 1982 // vertices 1983 var size_2 = particle.size / 2; 1984 if (particle.rotation) { 1985 var x1 = -size_2; 1986 var y1 = -size_2; 1987 1988 var x2 = size_2; 1989 var y2 = size_2; 1990 var x = newPosition.x; 1991 var y = newPosition.y; 1992 1993 var rad = -cc.DEGREES_TO_RADIANS(particle.rotation); 1994 var cr = Math.cos(rad); 1995 var sr = Math.sin(rad); 1996 var ax = x1 * cr - y1 * sr + x; 1997 var ay = x1 * sr + y1 * cr + y; 1998 var bx = x2 * cr - y1 * sr + x; 1999 var by = x2 * sr + y1 * cr + y; 2000 var cx = x2 * cr - y2 * sr + x; 2001 var cy = x2 * sr + y2 * cr + y; 2002 var dx = x1 * cr - y2 * sr + x; 2003 var dy = x1 * sr + y2 * cr + y; 2004 2005 // bottom-left 2006 quad.bl.vertices.x = ax; 2007 quad.bl.vertices.y = ay; 2008 2009 // bottom-right vertex: 2010 quad.br.vertices.x = bx; 2011 quad.br.vertices.y = by; 2012 2013 // top-left vertex: 2014 quad.tl.vertices.x = dx; 2015 quad.tl.vertices.y = dy; 2016 2017 // top-right vertex: 2018 quad.tr.vertices.x = cx; 2019 quad.tr.vertices.y = cy; 2020 } else { 2021 // bottom-left vertex: 2022 quad.bl.vertices.x = newPosition.x - size_2; 2023 quad.bl.vertices.y = newPosition.y - size_2; 2024 2025 // bottom-right vertex: 2026 quad.br.vertices.x = newPosition.x + size_2; 2027 quad.br.vertices.y = newPosition.y - size_2; 2028 2029 // top-left vertex: 2030 quad.tl.vertices.x = newPosition.x - size_2; 2031 quad.tl.vertices.y = newPosition.y + size_2; 2032 2033 // top-right vertex: 2034 quad.tr.vertices.x = newPosition.x + size_2; 2035 quad.tr.vertices.y = newPosition.y + size_2; 2036 } 2037 }, 2038 2039 /** 2040 * should be overridden by subclasses 2041 */ 2042 postStep:function () { 2043 if (cc.renderContextType === cc.WEBGL) { 2044 var gl = cc.renderContext; 2045 2046 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2047 gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); 2048 2049 // Option 2: Data 2050 // glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * particleCount, quads_, GL_DYNAMIC_DRAW); 2051 2052 // Option 3: Orphaning + glMapBuffer 2053 // glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*m_uTotalParticles, NULL, GL_STREAM_DRAW); 2054 // void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); 2055 // memcpy(buf, m_pQuads, sizeof(m_pQuads[0])*m_uTotalParticles); 2056 // glUnmapBuffer(GL_ARRAY_BUFFER); 2057 2058 //cc.CHECK_GL_ERROR_DEBUG(); 2059 } 2060 }, 2061 2062 /** 2063 * update emitter's status 2064 * @override 2065 * @param {Number} dt delta time 2066 */ 2067 update:function (dt) { 2068 if (this._isActive && this._emissionRate) { 2069 var rate = 1.0 / this._emissionRate; 2070 //issue #1201, prevent bursts of particles, due to too high emitCounter 2071 if (this._particleCount < this._totalParticles) 2072 this._emitCounter += dt; 2073 2074 while ((this._particleCount < this._totalParticles) && (this._emitCounter > rate)) { 2075 this.addParticle(); 2076 this._emitCounter -= rate; 2077 } 2078 2079 this._elapsed += dt; 2080 if (this._duration != -1 && this._duration < this._elapsed) 2081 this.stopSystem(); 2082 } 2083 this._particleIdx = 0; 2084 2085 var currentPosition = cc.Particle.TemporaryPoints[0]; 2086 if (this._positionType == cc.PARTICLE_TYPE_FREE) { 2087 cc.pIn(currentPosition, this.convertToWorldSpace(this._pointZeroForParticle)); 2088 } else if (this._positionType == cc.PARTICLE_TYPE_RELATIVE) { 2089 currentPosition.x = this._position.x; 2090 currentPosition.y = this._position.y; 2091 } 2092 2093 if (this._visible) { 2094 2095 // Used to reduce memory allocation / creation within the loop 2096 var tpa = cc.Particle.TemporaryPoints[1], 2097 tpb = cc.Particle.TemporaryPoints[2], 2098 tpc = cc.Particle.TemporaryPoints[3]; 2099 2100 var locParticles = this._particles; 2101 while (this._particleIdx < this._particleCount) { 2102 2103 // Reset the working particles 2104 cc.pZeroIn(tpa); 2105 cc.pZeroIn(tpb); 2106 cc.pZeroIn(tpc); 2107 2108 var selParticle = locParticles[this._particleIdx]; 2109 2110 // life 2111 selParticle.timeToLive -= dt; 2112 2113 if (selParticle.timeToLive > 0) { 2114 // Mode A: gravity, direction, tangential accel & radial accel 2115 if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) { 2116 2117 var tmp = tpc, radial = tpa, tangential = tpb; 2118 2119 // radial acceleration 2120 if (selParticle.pos.x || selParticle.pos.y) { 2121 cc.pIn(radial, selParticle.pos); 2122 cc.pNormalizeIn(radial); 2123 } else { 2124 cc.pZeroIn(radial); 2125 } 2126 2127 cc.pIn(tangential, radial); 2128 cc.pMultIn(radial, selParticle.modeA.radialAccel); 2129 2130 // tangential acceleration 2131 var newy = tangential.x; 2132 tangential.x = -tangential.y; 2133 tangential.y = newy; 2134 2135 cc.pMultIn(tangential, selParticle.modeA.tangentialAccel); 2136 2137 cc.pIn(tmp, radial); 2138 cc.pAddIn(tmp, tangential); 2139 cc.pAddIn(tmp, this.modeA.gravity); 2140 cc.pMultIn(tmp, dt); 2141 cc.pAddIn(selParticle.modeA.dir, tmp); 2142 2143 2144 cc.pIn(tmp, selParticle.modeA.dir); 2145 cc.pMultIn(tmp, dt); 2146 cc.pAddIn(selParticle.pos, tmp); 2147 2148 } else { 2149 // Mode B: radius movement 2150 var selModeB = selParticle.modeB; 2151 // Update the angle and radius of the particle. 2152 selModeB.angle += selModeB.degreesPerSecond * dt; 2153 selModeB.radius += selModeB.deltaRadius * dt; 2154 2155 selParticle.pos.x = -Math.cos(selModeB.angle) * selModeB.radius; 2156 selParticle.pos.y = -Math.sin(selModeB.angle) * selModeB.radius; 2157 } 2158 2159 // color 2160 if (!this._dontTint) { 2161 selParticle.color.r += (selParticle.deltaColor.r * dt); 2162 selParticle.color.g += (selParticle.deltaColor.g * dt); 2163 selParticle.color.b += (selParticle.deltaColor.b * dt); 2164 selParticle.color.a += (selParticle.deltaColor.a * dt); 2165 selParticle.isChangeColor = true; 2166 } 2167 2168 // size 2169 selParticle.size += (selParticle.deltaSize * dt); 2170 selParticle.size = Math.max(0, selParticle.size); 2171 2172 // angle 2173 selParticle.rotation += (selParticle.deltaRotation * dt); 2174 2175 // 2176 // update values in quad 2177 // 2178 var newPos = tpa; 2179 if (this._positionType == cc.PARTICLE_TYPE_FREE || this._positionType == cc.PARTICLE_TYPE_RELATIVE) { 2180 2181 var diff = tpb; 2182 cc.pIn(diff, currentPosition); 2183 cc.pSubIn(diff, selParticle.startPos); 2184 2185 cc.pIn(newPos, selParticle.pos); 2186 cc.pSubIn(newPos, diff); 2187 2188 } else { 2189 cc.pIn(newPos, selParticle.pos); 2190 } 2191 2192 // translate newPos to correct position, since matrix transform isn't performed in batchnode 2193 // don't update the particle with the new position information, it will interfere with the radius and tangential calculations 2194 if (this._batchNode) { 2195 newPos.x += this._position._x; 2196 newPos.y += this._position._y; 2197 } 2198 2199 if (cc.renderContextType == cc.WEBGL) { 2200 // IMPORTANT: newPos may not be used as a reference here! (as it is just the temporary tpa point) 2201 // the implementation of updateQuadWithParticle must use 2202 // the x and y values directly 2203 this.updateQuadWithParticle(selParticle, newPos); 2204 } else { 2205 cc.pIn(selParticle.drawPos, newPos); 2206 } 2207 //updateParticleImp(self, updateParticleSel, p, newPos); 2208 2209 // update particle counter 2210 ++this._particleIdx; 2211 } else { 2212 // life < 0 2213 var currentIndex = selParticle.atlasIndex; 2214 if(this._particleIdx !== this._particleCount -1){ 2215 var deadParticle = locParticles[this._particleIdx]; 2216 locParticles[this._particleIdx] = locParticles[this._particleCount -1]; 2217 locParticles[this._particleCount -1] = deadParticle; 2218 } 2219 if (this._batchNode) { 2220 //disable the switched particle 2221 this._batchNode.disableParticle(this._atlasIndex + currentIndex); 2222 2223 //switch indexes 2224 locParticles[this._particleCount - 1].atlasIndex = currentIndex; 2225 } 2226 2227 --this._particleCount; 2228 if (this._particleCount == 0 && this._isAutoRemoveOnFinish) { 2229 this.unscheduleUpdate(); 2230 this._parent.removeChild(this, true); 2231 return; 2232 } 2233 } 2234 } 2235 this._transformSystemDirty = false; 2236 } 2237 2238 if (!this._batchNode) 2239 this.postStep(); 2240 }, 2241 2242 updateWithNoTime:function () { 2243 this.update(0); 2244 }, 2245 2246 /** 2247 * return the string found by key in dict. 2248 * @param {string} key 2249 * @param {object} dict 2250 * @return {String} "" if not found; return the string if found. 2251 * @private 2252 */ 2253 _valueForKey:function (key, dict) { 2254 if (dict) { 2255 var pString = dict[key]; 2256 return pString != null ? pString : ""; 2257 } 2258 return ""; 2259 }, 2260 2261 _updateBlendFunc:function () { 2262 if(this._batchNode){ 2263 cc.log("Can't change blending functions when the particle is being batched"); 2264 return; 2265 } 2266 2267 var locTexture = this._texture; 2268 if (locTexture && locTexture instanceof cc.Texture2D) { 2269 this._opacityModifyRGB = false; 2270 var locBlendFunc = this._blendFunc; 2271 if (locBlendFunc.src == cc.BLEND_SRC && locBlendFunc.dst == cc.BLEND_DST) { 2272 if (locTexture.hasPremultipliedAlpha()) { 2273 this._opacityModifyRGB = true; 2274 } else { 2275 locBlendFunc.src = gl.SRC_ALPHA; 2276 locBlendFunc.dst = gl.ONE_MINUS_SRC_ALPHA; 2277 } 2278 } 2279 } 2280 }, 2281 2282 clone:function () { 2283 var retParticle = new cc.ParticleSystem(); 2284 2285 // self, not super 2286 if (retParticle.initWithTotalParticles(this._totalParticles)) { 2287 // angle 2288 retParticle._angle = this._angle; 2289 retParticle._angleVar = this._angleVar; 2290 2291 // duration 2292 retParticle._duration = this._duration; 2293 2294 // blend function 2295 retParticle._blendFunc.src = this._blendFunc.src; 2296 retParticle._blendFunc.dst = this._blendFunc.dst; 2297 2298 // color 2299 var particleStartColor = retParticle._startColor, locStartColor = this._startColor; 2300 particleStartColor.r = locStartColor.r; 2301 particleStartColor.g = locStartColor.g; 2302 particleStartColor.b = locStartColor.b; 2303 particleStartColor.a = locStartColor.a; 2304 2305 var particleStartColorVar = retParticle._startColorVar, locStartColorVar = this._startColorVar; 2306 particleStartColorVar.r = locStartColorVar.r; 2307 particleStartColorVar.g = locStartColorVar.g; 2308 particleStartColorVar.b = locStartColorVar.b; 2309 particleStartColorVar.a = locStartColorVar.a; 2310 2311 var particleEndColor = retParticle._endColor, locEndColor = this._endColor; 2312 particleEndColor.r = locEndColor.r; 2313 particleEndColor.g = locEndColor.g; 2314 particleEndColor.b = locEndColor.b; 2315 particleEndColor.a = locEndColor.a; 2316 2317 var particleEndColorVar = retParticle._endColorVar, locEndColorVar = this._endColorVar; 2318 particleEndColorVar.r = locEndColorVar.r; 2319 particleEndColorVar.g = locEndColorVar.g; 2320 particleEndColorVar.b = locEndColorVar.b; 2321 particleEndColorVar.a = locEndColorVar.a; 2322 2323 // particle size 2324 retParticle._startSize = this._startSize; 2325 retParticle._startSizeVar = this._startSizeVar; 2326 retParticle._endSize = this._endSize; 2327 retParticle._endSizeVar = this._endSizeVar; 2328 2329 // position 2330 retParticle.setPosition(this._position._x, this._position._y); 2331 retParticle._posVar.x = this._posVar.x; 2332 retParticle._posVar.y = this._posVar.y; 2333 2334 // Spinning 2335 retParticle._startSpin = this._startSpin; 2336 retParticle._startSpinVar = this._startSpinVar; 2337 retParticle._endSpin = this._endSpin; 2338 retParticle._endSpinVar = this._endSpinVar; 2339 2340 retParticle._emitterMode = this._emitterMode; 2341 2342 // Mode A: Gravity + tangential accel + radial accel 2343 if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) { 2344 var particleModeA = retParticle.modeA, locModeA = this.modeA; 2345 // gravity 2346 particleModeA.gravity.x = locModeA.gravity.x; 2347 particleModeA.gravity.y = locModeA.gravity.y; 2348 2349 // speed 2350 particleModeA.speed = locModeA.speed; 2351 particleModeA.speedVar = locModeA.speedVar; 2352 2353 // radial acceleration 2354 particleModeA.radialAccel = locModeA.radialAccel; 2355 2356 particleModeA.radialAccelVar = locModeA.radialAccelVar; 2357 2358 // tangential acceleration 2359 particleModeA.tangentialAccel = locModeA.tangentialAccel; 2360 2361 particleModeA.tangentialAccelVar = locModeA.tangentialAccelVar; 2362 } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) { 2363 var particleModeB = retParticle.modeB, locModeB = this.modeB; 2364 // or Mode B: radius movement 2365 particleModeB.startRadius = locModeB.startRadius; 2366 particleModeB.startRadiusVar = locModeB.startRadiusVar; 2367 particleModeB.endRadius = locModeB.endRadius; 2368 particleModeB.endRadiusVar = locModeB.endRadiusVar; 2369 particleModeB.rotatePerSecond = locModeB.rotatePerSecond; 2370 particleModeB.rotatePerSecondVar = locModeB.rotatePerSecondVar; 2371 } 2372 2373 // life span 2374 retParticle._life = this._life; 2375 retParticle._lifeVar = this._lifeVar; 2376 2377 // emission Rate 2378 retParticle._emissionRate = this._emissionRate; 2379 2380 //don't get the internal texture if a batchNode is used 2381 if (!this._batchNode) { 2382 // Set a compatible default for the alpha transfer 2383 retParticle._opacityModifyRGB = this._opacityModifyRGB; 2384 2385 // texture 2386 retParticle._texture = this._texture; 2387 } 2388 } 2389 return retParticle; 2390 }, 2391 2392 /** 2393 * <p> Sets a new CCSpriteFrame as particle.</br> 2394 * WARNING: this method is experimental. Use setTextureWithRect instead. 2395 * </p> 2396 * @param {cc.SpriteFrame} spriteFrame 2397 */ 2398 setDisplayFrame:function (spriteFrame) { 2399 var locOffset = spriteFrame.getOffsetInPixels(); 2400 if(locOffset.x != 0 || locOffset.y != 0) 2401 cc.log("cc.ParticleSystem.setDisplayFrame(): QuadParticle only supports SpriteFrames with no offsets"); 2402 2403 // update texture before updating texture rect 2404 if (cc.renderContextType === cc.WEBGL) 2405 if (!this._texture || spriteFrame.getTexture()._webTextureObj != this._texture._webTextureObj) 2406 this.setTexture(spriteFrame.getTexture()); 2407 }, 2408 2409 /** 2410 * Sets a new texture with a rect. The rect is in Points. 2411 * @param {cc.Texture2D} texture 2412 * @param {cc.Rect} rect 2413 */ 2414 setTextureWithRect:function (texture, rect) { 2415 var locTexture = this._texture; 2416 if (cc.renderContextType === cc.WEBGL) { 2417 // Only update the texture if is different from the current one 2418 if ((!locTexture || texture._webTextureObj != locTexture._webTextureObj) && (locTexture != texture)) { 2419 this._texture = texture; 2420 this._updateBlendFunc(); 2421 } 2422 } else { 2423 if ((!locTexture || texture != locTexture) && (locTexture != texture)) { 2424 this._texture = texture; 2425 this._updateBlendFunc(); 2426 } 2427 } 2428 2429 this._pointRect = rect; 2430 this.initTexCoordsWithRect(rect); 2431 }, 2432 2433 /** 2434 * draw particle 2435 * @param {CanvasRenderingContext2D} ctx CanvasContext 2436 * @override 2437 */ 2438 draw:function (ctx) { 2439 if(!this._textureLoaded || this._batchNode) // draw should not be called when added to a particleBatchNode 2440 return; 2441 2442 if (cc.renderContextType === cc.CANVAS) 2443 this._drawForCanvas(ctx); 2444 else 2445 this._drawForWebGL(ctx); 2446 2447 cc.g_NumberOfDraws++; 2448 }, 2449 2450 _drawForCanvas:function (ctx) { 2451 var context = ctx || cc.renderContext; 2452 context.save(); 2453 if (this.isBlendAdditive()) 2454 context.globalCompositeOperation = 'lighter'; 2455 else 2456 context.globalCompositeOperation = 'source-over'; 2457 2458 for (var i = 0; i < this._particleCount; i++) { 2459 var particle = this._particles[i]; 2460 var lpx = (0 | (particle.size * 0.5)); 2461 2462 if (this._drawMode == cc.PARTICLE_TEXTURE_MODE) { 2463 2464 var element = this._texture.getHtmlElementObj(); 2465 2466 // Delay drawing until the texture is fully loaded by the browser 2467 if (!element.width || !element.height) 2468 continue; 2469 2470 context.save(); 2471 context.globalAlpha = particle.color.a; 2472 context.translate((0 | particle.drawPos.x), -(0 | particle.drawPos.y)); 2473 2474 var size = Math.floor(particle.size / 4) * 4; 2475 var w = this._pointRect.width; 2476 var h = this._pointRect.height; 2477 2478 context.scale( 2479 Math.max((1 / w) * size, 0.000001), 2480 Math.max((1 / h) * size, 0.000001) 2481 ); 2482 2483 2484 if (particle.rotation) 2485 context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation)); 2486 2487 context.translate(-(0 | (w / 2)), -(0 | (h / 2))); 2488 if (particle.isChangeColor) { 2489 2490 var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(element); 2491 if (cacheTextureForColor) { 2492 // Create another cache for the tinted version 2493 // This speeds up things by a fair bit 2494 if (!cacheTextureForColor.tintCache) { 2495 cacheTextureForColor.tintCache = document.createElement('canvas'); 2496 cacheTextureForColor.tintCache.width = element.width; 2497 cacheTextureForColor.tintCache.height = element.height; 2498 } 2499 cc.generateTintImage(element, cacheTextureForColor, particle.color, this._pointRect, cacheTextureForColor.tintCache); 2500 element = cacheTextureForColor.tintCache; 2501 } 2502 } 2503 2504 context.drawImage(element, 0, 0); 2505 context.restore(); 2506 2507 } else { 2508 context.save(); 2509 context.globalAlpha = particle.color.a; 2510 2511 context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y)); 2512 2513 if (this._shapeType == cc.PARTICLE_STAR_SHAPE) { 2514 if (particle.rotation) 2515 context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation)); 2516 cc.drawingUtil.drawStar(context, lpx, particle.color); 2517 } else 2518 cc.drawingUtil.drawColorBall(context, lpx, particle.color); 2519 context.restore(); 2520 } 2521 } 2522 context.restore(); 2523 }, 2524 2525 _drawForWebGL:function (ctx) { 2526 if(!this._texture) 2527 return; 2528 2529 var gl = ctx || cc.renderContext; 2530 2531 this._shaderProgram.use(); 2532 this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); 2533 2534 cc.glBindTexture2D(this._texture); 2535 cc.glBlendFuncForParticle(this._blendFunc.src, this._blendFunc.dst); 2536 2537 //cc.Assert(this._particleIdx == this._particleCount, "Abnormal error in particle quad"); 2538 2539 // 2540 // Using VBO without VAO 2541 // 2542 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSCOLORTEX); 2543 2544 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2545 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); // vertices 2546 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); // colors 2547 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16); // tex coords 2548 2549 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2550 gl.drawElements(gl.TRIANGLES, this._particleIdx * 6, gl.UNSIGNED_SHORT, 0); 2551 }, 2552 2553 /** 2554 * listen the event that coming to foreground on Android 2555 * @param {cc.Class} obj 2556 */ 2557 listenBackToForeground:function (obj) { 2558 if (cc.TEXTURE_ATLAS_USE_VAO) 2559 this._setupVBOandVAO(); 2560 else 2561 this._setupVBO(); 2562 }, 2563 2564 _setupVBOandVAO:function () { 2565 //Not support on WebGL 2566 /*if (cc.renderContextType == cc.CANVAS) { 2567 return; 2568 }*/ 2569 2570 //NOT SUPPORTED 2571 /*glGenVertexArrays(1, this._VAOname); 2572 glBindVertexArray(this._VAOname); 2573 2574 var kQuadSize = sizeof(m_pQuads[0].bl); 2575 2576 glGenBuffers(2, this._buffersVBO[0]); 2577 2578 glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]); 2579 glBufferData(GL_ARRAY_BUFFER, sizeof(this._quads[0]) * this._totalParticles, this._quads, GL_DYNAMIC_DRAW); 2580 2581 // vertices 2582 glEnableVertexAttribArray(kCCVertexAttrib_Position); 2583 glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, vertices)); 2584 2585 // colors 2586 glEnableVertexAttribArray(kCCVertexAttrib_Color); 2587 glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, offsetof(ccV3F_C4B_T2F, colors)); 2588 2589 // tex coords 2590 glEnableVertexAttribArray(kCCVertexAttrib_TexCoords); 2591 glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, texCoords)); 2592 2593 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2594 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW); 2595 2596 glBindVertexArray(0); 2597 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 2598 glBindBuffer(GL_ARRAY_BUFFER, 0); 2599 2600 CHECK_GL_ERROR_DEBUG();*/ 2601 }, 2602 2603 _setupVBO:function () { 2604 if (cc.renderContextType == cc.CANVAS) 2605 return; 2606 2607 var gl = cc.renderContext; 2608 2609 //gl.deleteBuffer(this._buffersVBO[0]); 2610 this._buffersVBO[0] = gl.createBuffer(); 2611 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2612 gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); 2613 2614 this._buffersVBO[1] = gl.createBuffer(); 2615 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2616 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW); 2617 2618 //cc.CHECK_GL_ERROR_DEBUG(); 2619 }, 2620 2621 _allocMemory:function () { 2622 if (cc.renderContextType === cc.CANVAS) 2623 return true; 2624 2625 //cc.Assert((!this._quads && !this._indices), "Memory already allocated"); 2626 if(this._batchNode){ 2627 cc.log("cc.ParticleSystem._allocMemory(): Memory should not be allocated when not using batchNode"); 2628 return false; 2629 } 2630 2631 var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; 2632 var totalParticles = this._totalParticles; 2633 var locQuads = this._quads; 2634 locQuads.length = 0; 2635 this._indices = new Uint16Array(totalParticles * 6); 2636 var locQuadsArrayBuffer = new ArrayBuffer(quadSize * totalParticles); 2637 2638 for (var i = 0; i < totalParticles; i++) 2639 locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, i * quadSize); 2640 if (!locQuads || !this._indices) { 2641 cc.log("cocos2d: Particle system: not enough memory"); 2642 return false; 2643 } 2644 this._quadsArrayBuffer = locQuadsArrayBuffer; 2645 return true; 2646 } 2647 }); 2648 2649 /** 2650 * <p> return the string found by key in dict. <br/> 2651 * This plist files can be create manually or with Particle Designer:<br/> 2652 * http://particledesigner.71squared.com/<br/> 2653 * </p> 2654 * @param {String} plistFile 2655 * @return {cc.ParticleSystem} 2656 */ 2657 cc.ParticleSystem.create = function (plistFile) { 2658 var ret = new cc.ParticleSystem(); 2659 if (!plistFile || typeof(plistFile) === "number") { 2660 var ton = plistFile || 100; 2661 ret.setDrawMode(cc.PARTICLE_TEXTURE_MODE); 2662 ret.initWithTotalParticles(ton); 2663 return ret; 2664 } 2665 2666 if (ret && ret.initWithFile(plistFile)) 2667 return ret; 2668 return null; 2669 }; 2670 2671 /** 2672 * create a system with a fixed number of particles 2673 * @param {Number} number_of_particles 2674 * @return {cc.ParticleSystem} 2675 */ 2676 cc.ParticleSystem.createWithTotalParticles = function (number_of_particles) { 2677 //emitter.initWithTotalParticles(number_of_particles); 2678 var particle = new cc.ParticleSystem(); 2679 if (particle && particle.initWithTotalParticles(number_of_particles)) 2680 return particle; 2681 return null; 2682 }; 2683 2684 // Different modes 2685 /** 2686 * Mode A:Gravity + Tangential Accel + Radial Accel 2687 * @Class 2688 * @Construct 2689 * @param {cc.Point} [gravity=] Gravity value. 2690 * @param {Number} [speed=0] speed of each particle. 2691 * @param {Number} [speedVar=0] speed variance of each particle. 2692 * @param {Number} [tangentialAccel=0] tangential acceleration of each particle. 2693 * @param {Number} [tangentialAccelVar=0] tangential acceleration variance of each particle. 2694 * @param {Number} [radialAccel=0] radial acceleration of each particle. 2695 * @param {Number} [radialAccelVar=0] radial acceleration variance of each particle. 2696 * @param {boolean} [rotationIsDir=false] 2697 */ 2698 cc.ParticleSystem.ModeA = function (gravity, speed, speedVar, tangentialAccel, tangentialAccelVar, radialAccel, radialAccelVar, rotationIsDir) { 2699 /** Gravity value. Only available in 'Gravity' mode. */ 2700 this.gravity = gravity ? gravity : cc.PointZero(); 2701 /** speed of each particle. Only available in 'Gravity' mode. */ 2702 this.speed = speed || 0; 2703 /** speed variance of each particle. Only available in 'Gravity' mode. */ 2704 this.speedVar = speedVar || 0; 2705 /** tangential acceleration of each particle. Only available in 'Gravity' mode. */ 2706 this.tangentialAccel = tangentialAccel || 0; 2707 /** tangential acceleration variance of each particle. Only available in 'Gravity' mode. */ 2708 this.tangentialAccelVar = tangentialAccelVar || 0; 2709 /** radial acceleration of each particle. Only available in 'Gravity' mode. */ 2710 this.radialAccel = radialAccel || 0; 2711 /** radial acceleration variance of each particle. Only available in 'Gravity' mode. */ 2712 this.radialAccelVar = radialAccelVar || 0; 2713 /** set the rotation of each particle to its direction Only available in 'Gravity' mode. */ 2714 this.rotationIsDir = rotationIsDir || false; 2715 }; 2716 2717 /** 2718 * Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) 2719 * @Class 2720 * @Construct 2721 * @param {Number} startRadius The starting radius of the particles. 2722 * @param {Number} startRadiusVar The starting radius variance of the particles. 2723 * @param {Number} endRadius The ending radius of the particles. 2724 * @param {Number} endRadiusVar The ending radius variance of the particles. 2725 * @param {Number} rotatePerSecond Number of degress to rotate a particle around the source pos per second. 2726 * @param {Number} rotatePerSecondVar Variance in degrees for rotatePerSecond. 2727 */ 2728 cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endRadiusVar, rotatePerSecond, rotatePerSecondVar) { 2729 /** The starting radius of the particles. Only available in 'Radius' mode. */ 2730 this.startRadius = startRadius || 0; 2731 /** The starting radius variance of the particles. Only available in 'Radius' mode. */ 2732 this.startRadiusVar = startRadiusVar || 0; 2733 /** The ending radius of the particles. Only available in 'Radius' mode. */ 2734 this.endRadius = endRadius || 0; 2735 /** The ending radius variance of the particles. Only available in 'Radius' mode. */ 2736 this.endRadiusVar = endRadiusVar || 0; 2737 /** Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. */ 2738 this.rotatePerSecond = rotatePerSecond || 0; 2739 /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */ 2740 this.rotatePerSecondVar = rotatePerSecondVar || 0; 2741 }; 2742