├── Cocos2dx-particles.txt ├── ParticleExample.cpp ├── ParticleExample.h ├── ParticleSystem.cpp ├── ParticleSystem.h ├── README.md ├── fire.png ├── main.cpp └── pic ├── fire.png └── snow.png /Cocos2dx-particles.txt: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | Copyright (c) 2008-2010 Ricardo Quesada 3 | Copyright (c) 2010-2012 cocos2d-x.org 4 | Copyright (c) 2011 Zynga Inc. 5 | Copyright (c) 2013-2016 Chukong Technologies Inc. 6 | Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. 7 | 8 | http://www.cocos2d-x.org 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | ****************************************************************************/ 28 | 29 | // ideas taken from: 30 | // . The ocean spray in your face [Jeff Lander] 31 | // http://www.double.co.nz/dust/col0798.pdf 32 | // . Building an Advanced Particle System [John van der Burg] 33 | // http://www.gamasutra.com/features/20000623/vanderburg_01.htm 34 | // . LOVE game engine 35 | // http://love2d.org/ 36 | // 37 | // 38 | // Radius mode support, from 71 squared 39 | // http://particledesigner.71squared.com/ 40 | // 41 | // IMPORTANT: Particle Designer is supported by cocos2d, but 42 | // 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guaranteed in cocos2d, 43 | // cocos2d uses a another approach, but the results are almost identical. 44 | // -------------------------------------------------------------------------------- /ParticleExample.cpp: -------------------------------------------------------------------------------- 1 | #include "ParticleExample.h" 2 | 3 | void ParticleExample::setStyle(PatticleStyle style) 4 | { 5 | if (style_ == style) 6 | { 7 | return; 8 | } 9 | style_ = style; 10 | if (style == NONE) 11 | { 12 | stopSystem(); 13 | } 14 | if (_texture == nullptr) 15 | { 16 | setTexture(getDefaultTexture()); 17 | } 18 | switch (style) 19 | { 20 | case ParticleExample::FIRE: 21 | { 22 | initWithTotalParticles(250); 23 | 24 | // duration 25 | _duration = DURATION_INFINITY; 26 | 27 | // Gravity Mode 28 | this->_emitterMode = Mode::GRAVITY; 29 | 30 | // Gravity Mode: gravity 31 | this->modeA.gravity = { 0, 0 }; 32 | 33 | // Gravity Mode: radial acceleration 34 | this->modeA.radialAccel = 0; 35 | this->modeA.radialAccelVar = 0; 36 | 37 | // Gravity Mode: speed of particles 38 | this->modeA.speed = -60; 39 | this->modeA.speedVar = 20; 40 | 41 | // starting angle 42 | _angle = 90; 43 | _angleVar = 10; 44 | 45 | // life of particles 46 | _life = 3; 47 | _lifeVar = 0.25f; 48 | 49 | // size, in pixels 50 | _startSize = 54.0f; 51 | _startSizeVar = 10.0f; 52 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 53 | 54 | // emits per frame 55 | _emissionRate = _totalParticles / _life; 56 | 57 | // color of particles 58 | _startColor.r = 0.76f; 59 | _startColor.g = 0.25f; 60 | _startColor.b = 0.12f; 61 | _startColor.a = 1.0f; 62 | _startColorVar.r = 0.0f; 63 | _startColorVar.g = 0.0f; 64 | _startColorVar.b = 0.0f; 65 | _startColorVar.a = 0.0f; 66 | _endColor.r = 0.0f; 67 | _endColor.g = 0.0f; 68 | _endColor.b = 0.0f; 69 | _endColor.a = 0.0f; 70 | _endColorVar.r = 0.0f; 71 | _endColorVar.g = 0.0f; 72 | _endColorVar.b = 0.0f; 73 | _endColorVar.a = 0.0f; 74 | 75 | _posVar = { 40.0f, 20.0f }; 76 | break; 77 | } 78 | case ParticleExample::FIRE_WORK: 79 | { 80 | initWithTotalParticles(1500); 81 | 82 | // duration 83 | _duration = DURATION_INFINITY; 84 | 85 | // Gravity Mode 86 | this->_emitterMode = Mode::GRAVITY; 87 | 88 | // Gravity Mode: gravity 89 | this->modeA.gravity = { 0.0f, 90.0f }; 90 | 91 | // Gravity Mode: radial 92 | this->modeA.radialAccel = 0.0f; 93 | this->modeA.radialAccelVar = 0.0f; 94 | 95 | // Gravity Mode: speed of particles 96 | this->modeA.speed = -180.0f; 97 | this->modeA.speedVar = 50.0f; 98 | 99 | // angle 100 | this->_angle = 90.0f; 101 | this->_angleVar = 20.0f; 102 | 103 | // life of particles 104 | this->_life = 3.5f; 105 | this->_lifeVar = 1.0f; 106 | 107 | // emits per frame 108 | this->_emissionRate = _totalParticles / _life; 109 | 110 | // color of particles 111 | _startColor.r = 0.5f; 112 | _startColor.g = 0.5f; 113 | _startColor.b = 0.5f; 114 | _startColor.a = 1.0f; 115 | _startColorVar.r = 0.5f; 116 | _startColorVar.g = 0.5f; 117 | _startColorVar.b = 0.5f; 118 | _startColorVar.a = 0.1f; 119 | _endColor.r = 0.1f; 120 | _endColor.g = 0.1f; 121 | _endColor.b = 0.1f; 122 | _endColor.a = 0.2f; 123 | _endColorVar.r = 0.1f; 124 | _endColorVar.g = 0.1f; 125 | _endColorVar.b = 0.1f; 126 | _endColorVar.a = 0.2f; 127 | 128 | // size, in pixels 129 | _startSize = 8.0f; 130 | _startSizeVar = 2.0f; 131 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 132 | 133 | _posVar = { 0, 0 }; 134 | break; 135 | } 136 | case ParticleExample::SUN: 137 | { 138 | initWithTotalParticles(350); 139 | 140 | // additive 141 | //this->setBlendAdditive(true); 142 | 143 | // duration 144 | _duration = DURATION_INFINITY; 145 | 146 | // Gravity Mode 147 | setEmitterMode(Mode::GRAVITY); 148 | 149 | // Gravity Mode: gravity 150 | setGravity(Vec2(0, 0)); 151 | 152 | // Gravity mode: radial acceleration 153 | setRadialAccel(0); 154 | setRadialAccelVar(0); 155 | 156 | // Gravity mode: speed of particles 157 | setSpeed(-20); 158 | setSpeedVar(5); 159 | 160 | // angle 161 | _angle = 90; 162 | _angleVar = 360; 163 | 164 | // life of particles 165 | _life = 1; 166 | _lifeVar = 0.5f; 167 | 168 | // size, in pixels 169 | _startSize = 30.0f; 170 | _startSizeVar = 10.0f; 171 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 172 | 173 | // emits per seconds 174 | _emissionRate = _totalParticles / _life; 175 | 176 | // color of particles 177 | _startColor.r = 0.76f; 178 | _startColor.g = 0.25f; 179 | _startColor.b = 0.12f; 180 | _startColor.a = 1.0f; 181 | _startColorVar.r = 0.0f; 182 | _startColorVar.g = 0.0f; 183 | _startColorVar.b = 0.0f; 184 | _startColorVar.a = 0.0f; 185 | _endColor.r = 0.0f; 186 | _endColor.g = 0.0f; 187 | _endColor.b = 0.0f; 188 | _endColor.a = 1.0f; 189 | _endColorVar.r = 0.0f; 190 | _endColorVar.g = 0.0f; 191 | _endColorVar.b = 0.0f; 192 | _endColorVar.a = 0.0f; 193 | 194 | _posVar = { 0, 0 }; 195 | break; 196 | } 197 | case ParticleExample::GALAXY: 198 | { 199 | initWithTotalParticles(200); 200 | // duration 201 | _duration = DURATION_INFINITY; 202 | 203 | // Gravity Mode 204 | setEmitterMode(Mode::GRAVITY); 205 | 206 | // Gravity Mode: gravity 207 | setGravity(Vec2(0, 0)); 208 | 209 | // Gravity Mode: speed of particles 210 | setSpeed(-60); 211 | setSpeedVar(10); 212 | 213 | // Gravity Mode: radial 214 | setRadialAccel(-80); 215 | setRadialAccelVar(0); 216 | 217 | // Gravity Mode: tangential 218 | setTangentialAccel(80); 219 | setTangentialAccelVar(0); 220 | 221 | // angle 222 | _angle = 90; 223 | _angleVar = 360; 224 | 225 | // life of particles 226 | _life = 4; 227 | _lifeVar = 1; 228 | 229 | // size, in pixels 230 | _startSize = 37.0f; 231 | _startSizeVar = 10.0f; 232 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 233 | 234 | // emits per second 235 | _emissionRate = _totalParticles / _life; 236 | 237 | // color of particles 238 | _startColor.r = 0.12f; 239 | _startColor.g = 0.25f; 240 | _startColor.b = 0.76f; 241 | _startColor.a = 1.0f; 242 | _startColorVar.r = 0.0f; 243 | _startColorVar.g = 0.0f; 244 | _startColorVar.b = 0.0f; 245 | _startColorVar.a = 0.0f; 246 | _endColor.r = 0.0f; 247 | _endColor.g = 0.0f; 248 | _endColor.b = 0.0f; 249 | _endColor.a = 1.0f; 250 | _endColorVar.r = 0.0f; 251 | _endColorVar.g = 0.0f; 252 | _endColorVar.b = 0.0f; 253 | _endColorVar.a = 0.0f; 254 | 255 | _posVar = { 0, 0 }; 256 | break; 257 | } 258 | case ParticleExample::FLOWER: 259 | { 260 | initWithTotalParticles(250); 261 | 262 | // duration 263 | _duration = DURATION_INFINITY; 264 | 265 | // Gravity Mode 266 | setEmitterMode(Mode::GRAVITY); 267 | 268 | // Gravity Mode: gravity 269 | setGravity(Vec2(0, 0)); 270 | 271 | // Gravity Mode: speed of particles 272 | setSpeed(-80); 273 | setSpeedVar(10); 274 | 275 | // Gravity Mode: radial 276 | setRadialAccel(-60); 277 | setRadialAccelVar(0); 278 | 279 | // Gravity Mode: tangential 280 | setTangentialAccel(15); 281 | setTangentialAccelVar(0); 282 | 283 | // angle 284 | _angle = 90; 285 | _angleVar = 360; 286 | 287 | // life of particles 288 | _life = 4; 289 | _lifeVar = 1; 290 | 291 | // size, in pixels 292 | _startSize = 30.0f; 293 | _startSizeVar = 10.0f; 294 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 295 | 296 | // emits per second 297 | _emissionRate = _totalParticles / _life; 298 | 299 | // color of particles 300 | _startColor.r = 0.50f; 301 | _startColor.g = 0.50f; 302 | _startColor.b = 0.50f; 303 | _startColor.a = 1.0f; 304 | _startColorVar.r = 0.5f; 305 | _startColorVar.g = 0.5f; 306 | _startColorVar.b = 0.5f; 307 | _startColorVar.a = 0.5f; 308 | _endColor.r = 0.0f; 309 | _endColor.g = 0.0f; 310 | _endColor.b = 0.0f; 311 | _endColor.a = 1.0f; 312 | _endColorVar.r = 0.0f; 313 | _endColorVar.g = 0.0f; 314 | _endColorVar.b = 0.0f; 315 | _endColorVar.a = 0.0f; 316 | 317 | _posVar = { 0, 0 }; 318 | break; 319 | } 320 | case ParticleExample::METEOR: 321 | { 322 | initWithTotalParticles(150); 323 | 324 | // duration 325 | _duration = DURATION_INFINITY; 326 | 327 | // Gravity Mode 328 | setEmitterMode(Mode::GRAVITY); 329 | 330 | // Gravity Mode: gravity 331 | setGravity(Vec2(-200, -200)); 332 | 333 | // Gravity Mode: speed of particles 334 | setSpeed(-15); 335 | setSpeedVar(5); 336 | 337 | // Gravity Mode: radial 338 | setRadialAccel(0); 339 | setRadialAccelVar(0); 340 | 341 | // Gravity Mode: tangential 342 | setTangentialAccel(0); 343 | setTangentialAccelVar(0); 344 | 345 | // angle 346 | _angle = 90; 347 | _angleVar = 360; 348 | 349 | // life of particles 350 | _life = 2; 351 | _lifeVar = 1; 352 | 353 | // size, in pixels 354 | _startSize = 60.0f; 355 | _startSizeVar = 10.0f; 356 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 357 | 358 | // emits per second 359 | _emissionRate = _totalParticles / _life; 360 | 361 | // color of particles 362 | _startColor.r = 0.2f; 363 | _startColor.g = 0.4f; 364 | _startColor.b = 0.7f; 365 | _startColor.a = 1.0f; 366 | _startColorVar.r = 0.0f; 367 | _startColorVar.g = 0.0f; 368 | _startColorVar.b = 0.2f; 369 | _startColorVar.a = 0.1f; 370 | _endColor.r = 0.0f; 371 | _endColor.g = 0.0f; 372 | _endColor.b = 0.0f; 373 | _endColor.a = 1.0f; 374 | _endColorVar.r = 0.0f; 375 | _endColorVar.g = 0.0f; 376 | _endColorVar.b = 0.0f; 377 | _endColorVar.a = 0.0f; 378 | 379 | _posVar = { 0, 0 }; 380 | break; 381 | } 382 | case ParticleExample::SPIRAL: 383 | { 384 | initWithTotalParticles(500); 385 | 386 | // duration 387 | _duration = DURATION_INFINITY; 388 | 389 | // Gravity Mode 390 | setEmitterMode(Mode::GRAVITY); 391 | 392 | // Gravity Mode: gravity 393 | setGravity(Vec2(0, 0)); 394 | 395 | // Gravity Mode: speed of particles 396 | setSpeed(-150); 397 | setSpeedVar(0); 398 | 399 | // Gravity Mode: radial 400 | setRadialAccel(-380); 401 | setRadialAccelVar(0); 402 | 403 | // Gravity Mode: tangential 404 | setTangentialAccel(45); 405 | setTangentialAccelVar(0); 406 | 407 | // angle 408 | _angle = 90; 409 | _angleVar = 0; 410 | 411 | // life of particles 412 | _life = 12; 413 | _lifeVar = 0; 414 | 415 | // size, in pixels 416 | _startSize = 20.0f; 417 | _startSizeVar = 0.0f; 418 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 419 | 420 | // emits per second 421 | _emissionRate = _totalParticles / _life; 422 | 423 | // color of particles 424 | _startColor.r = 0.5f; 425 | _startColor.g = 0.5f; 426 | _startColor.b = 0.5f; 427 | _startColor.a = 1.0f; 428 | _startColorVar.r = 0.5f; 429 | _startColorVar.g = 0.5f; 430 | _startColorVar.b = 0.5f; 431 | _startColorVar.a = 0.0f; 432 | _endColor.r = 0.5f; 433 | _endColor.g = 0.5f; 434 | _endColor.b = 0.5f; 435 | _endColor.a = 1.0f; 436 | _endColorVar.r = 0.5f; 437 | _endColorVar.g = 0.5f; 438 | _endColorVar.b = 0.5f; 439 | _endColorVar.a = 0.0f; 440 | 441 | _posVar = { 0, 0 }; 442 | break; 443 | } 444 | case ParticleExample::EXPLOSION: 445 | { 446 | initWithTotalParticles(700); 447 | 448 | // duration 449 | _duration = 0.1f; 450 | 451 | setEmitterMode(Mode::GRAVITY); 452 | 453 | // Gravity Mode: gravity 454 | setGravity(Vec2(0, 0)); 455 | 456 | // Gravity Mode: speed of particles 457 | setSpeed(-70); 458 | setSpeedVar(40); 459 | 460 | // Gravity Mode: radial 461 | setRadialAccel(0); 462 | setRadialAccelVar(0); 463 | 464 | // Gravity Mode: tangential 465 | setTangentialAccel(0); 466 | setTangentialAccelVar(0); 467 | 468 | // angle 469 | _angle = 90; 470 | _angleVar = 360; 471 | 472 | // life of particles 473 | _life = 5.0f; 474 | _lifeVar = 2; 475 | 476 | // size, in pixels 477 | _startSize = 15.0f; 478 | _startSizeVar = 10.0f; 479 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 480 | 481 | // emits per second 482 | _emissionRate = _totalParticles / _duration; 483 | 484 | // color of particles 485 | _startColor.r = 0.7f; 486 | _startColor.g = 0.1f; 487 | _startColor.b = 0.2f; 488 | _startColor.a = 1.0f; 489 | _startColorVar.r = 0.5f; 490 | _startColorVar.g = 0.5f; 491 | _startColorVar.b = 0.5f; 492 | _startColorVar.a = 0.0f; 493 | _endColor.r = 0.5f; 494 | _endColor.g = 0.5f; 495 | _endColor.b = 0.5f; 496 | _endColor.a = 0.0f; 497 | _endColorVar.r = 0.5f; 498 | _endColorVar.g = 0.5f; 499 | _endColorVar.b = 0.5f; 500 | _endColorVar.a = 0.0f; 501 | 502 | _posVar = { 0, 0 }; 503 | break; 504 | } 505 | case ParticleExample::SMOKE: 506 | { 507 | initWithTotalParticles(200); 508 | 509 | // duration 510 | _duration = DURATION_INFINITY; 511 | 512 | // Emitter mode: Gravity Mode 513 | setEmitterMode(Mode::GRAVITY); 514 | 515 | // Gravity Mode: gravity 516 | setGravity(Vec2(0, 0)); 517 | 518 | // Gravity Mode: radial acceleration 519 | setRadialAccel(0); 520 | setRadialAccelVar(0); 521 | 522 | // Gravity Mode: speed of particles 523 | setSpeed(-25); 524 | setSpeedVar(10); 525 | 526 | // angle 527 | _angle = 90; 528 | _angleVar = 5; 529 | 530 | // life of particles 531 | _life = 4; 532 | _lifeVar = 1; 533 | 534 | // size, in pixels 535 | _startSize = 60.0f; 536 | _startSizeVar = 10.0f; 537 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 538 | 539 | // emits per frame 540 | _emissionRate = _totalParticles / _life; 541 | 542 | // color of particles 543 | _startColor.r = 0.8f; 544 | _startColor.g = 0.8f; 545 | _startColor.b = 0.8f; 546 | _startColor.a = 1.0f; 547 | _startColorVar.r = 0.02f; 548 | _startColorVar.g = 0.02f; 549 | _startColorVar.b = 0.02f; 550 | _startColorVar.a = 0.0f; 551 | _endColor.r = 0.0f; 552 | _endColor.g = 0.0f; 553 | _endColor.b = 0.0f; 554 | _endColor.a = 1.0f; 555 | _endColorVar.r = 0.0f; 556 | _endColorVar.g = 0.0f; 557 | _endColorVar.b = 0.0f; 558 | _endColorVar.a = 0.0f; 559 | 560 | _posVar = { 20.0f, 0.0f }; 561 | break; 562 | } 563 | case ParticleExample::SNOW: 564 | { 565 | initWithTotalParticles(700); 566 | 567 | // duration 568 | _duration = DURATION_INFINITY; 569 | 570 | // set gravity mode. 571 | setEmitterMode(Mode::GRAVITY); 572 | 573 | // Gravity Mode: gravity 574 | setGravity(Vec2(0, 1)); 575 | 576 | // Gravity Mode: speed of particles 577 | setSpeed(-5); 578 | setSpeedVar(1); 579 | 580 | // Gravity Mode: radial 581 | setRadialAccel(0); 582 | setRadialAccelVar(1); 583 | 584 | // Gravity mode: tangential 585 | setTangentialAccel(0); 586 | setTangentialAccelVar(1); 587 | 588 | // angle 589 | _angle = -90; 590 | _angleVar = 5; 591 | 592 | // life of particles 593 | _life = 45; 594 | _lifeVar = 15; 595 | 596 | // size, in pixels 597 | _startSize = 10.0f; 598 | _startSizeVar = 5.0f; 599 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 600 | 601 | // emits per second 602 | _emissionRate = 10; 603 | 604 | // color of particles 605 | _startColor.r = 1.0f; 606 | _startColor.g = 1.0f; 607 | _startColor.b = 1.0f; 608 | _startColor.a = 1.0f; 609 | _startColorVar.r = 0.0f; 610 | _startColorVar.g = 0.0f; 611 | _startColorVar.b = 0.0f; 612 | _startColorVar.a = 0.0f; 613 | _endColor.r = 1.0f; 614 | _endColor.g = 1.0f; 615 | _endColor.b = 1.0f; 616 | _endColor.a = 0.0f; 617 | _endColorVar.r = 0.0f; 618 | _endColorVar.g = 0.0f; 619 | _endColorVar.b = 0.0f; 620 | _endColorVar.a = 0.0f; 621 | 622 | _posVar = { 1.0f * x_, 0.0f }; 623 | break; 624 | } 625 | case ParticleExample::RAIN: 626 | { 627 | initWithTotalParticles(1000); 628 | 629 | // duration 630 | _duration = DURATION_INFINITY; 631 | 632 | setEmitterMode(Mode::GRAVITY); 633 | 634 | // Gravity Mode: gravity 635 | setGravity(Vec2(10, 10)); 636 | 637 | // Gravity Mode: radial 638 | setRadialAccel(0); 639 | setRadialAccelVar(1); 640 | 641 | // Gravity Mode: tangential 642 | setTangentialAccel(0); 643 | setTangentialAccelVar(1); 644 | 645 | // Gravity Mode: speed of particles 646 | setSpeed(-130); 647 | setSpeedVar(30); 648 | 649 | // angle 650 | _angle = -90; 651 | _angleVar = 5; 652 | 653 | // life of particles 654 | _life = 4.5f; 655 | _lifeVar = 0; 656 | 657 | // size, in pixels 658 | _startSize = 4.0f; 659 | _startSizeVar = 2.0f; 660 | _endSize = START_SIZE_EQUAL_TO_END_SIZE; 661 | 662 | // emits per second 663 | _emissionRate = 20; 664 | 665 | // color of particles 666 | _startColor.r = 0.7f; 667 | _startColor.g = 0.8f; 668 | _startColor.b = 1.0f; 669 | _startColor.a = 1.0f; 670 | _startColorVar.r = 0.0f; 671 | _startColorVar.g = 0.0f; 672 | _startColorVar.b = 0.0f; 673 | _startColorVar.a = 0.0f; 674 | _endColor.r = 0.7f; 675 | _endColor.g = 0.8f; 676 | _endColor.b = 1.0f; 677 | _endColor.a = 0.5f; 678 | _endColorVar.r = 0.0f; 679 | _endColorVar.g = 0.0f; 680 | _endColorVar.b = 0.0f; 681 | _endColorVar.a = 0.0f; 682 | 683 | _posVar = { 1.0f * x_, 0.0f }; 684 | break; 685 | } 686 | default: 687 | break; 688 | } 689 | } 690 | -------------------------------------------------------------------------------- /ParticleExample.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ParticleSystem.h" 3 | #include "SDL2/SDL_image.h" 4 | 5 | class ParticleExample : public ParticleSystem 6 | { 7 | public: 8 | ParticleExample() {} 9 | virtual ~ParticleExample() {} 10 | 11 | enum PatticleStyle 12 | { 13 | NONE, 14 | FIRE, 15 | FIRE_WORK, 16 | SUN, 17 | GALAXY, 18 | FLOWER, 19 | METEOR, 20 | SPIRAL, 21 | EXPLOSION, 22 | SMOKE, 23 | SNOW, 24 | RAIN, 25 | }; 26 | 27 | PatticleStyle style_ = NONE; 28 | void setStyle(PatticleStyle style); 29 | SDL_Texture* getDefaultTexture() 30 | { 31 | static SDL_Texture* t = IMG_LoadTexture(_renderer, "fire.png"); 32 | //printf(SDL_GetError()); 33 | return t; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /ParticleSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "ParticleSystem.h" 2 | #include 3 | #include 4 | #include 5 | 6 | inline float Deg2Rad(float a) 7 | { 8 | return a * 0.01745329252f; 9 | } 10 | 11 | inline float Rad2Deg(float a) 12 | { 13 | return a * 57.29577951f; 14 | } 15 | 16 | inline float clampf(float value, float min_inclusive, float max_inclusive) 17 | { 18 | if (min_inclusive > max_inclusive) 19 | { 20 | std::swap(min_inclusive, max_inclusive); 21 | } 22 | return value < min_inclusive ? min_inclusive : value < max_inclusive ? value : max_inclusive; 23 | } 24 | 25 | inline void normalize_point(float x, float y, Pointf* out) 26 | { 27 | float n = x * x + y * y; 28 | // Already normalized. 29 | if (n == 1.0f) 30 | { 31 | return; 32 | } 33 | 34 | n = sqrt(n); 35 | // Too close to zero. 36 | if (n < 1e-5) 37 | { 38 | return; 39 | } 40 | 41 | n = 1.0f / n; 42 | out->x = x * n; 43 | out->y = y * n; 44 | } 45 | 46 | /** 47 | A more effect random number getter function, get from ejoy2d. 48 | */ 49 | inline static float RANDOM_M11(unsigned int* seed) 50 | { 51 | *seed = *seed * 134775813 + 1; 52 | union 53 | { 54 | uint32_t d; 55 | float f; 56 | } u; 57 | u.d = (((uint32_t)(*seed) & 0x7fff) << 8) | 0x40000000; 58 | return u.f - 3.0f; 59 | } 60 | 61 | ParticleSystem::ParticleSystem() 62 | { 63 | } 64 | 65 | // implementation ParticleSystem 66 | 67 | bool ParticleSystem::initWithTotalParticles(int numberOfParticles) 68 | { 69 | _totalParticles = numberOfParticles; 70 | _isActive = true; 71 | _emitterMode = Mode::GRAVITY; 72 | _isAutoRemoveOnFinish = false; 73 | _transformSystemDirty = false; 74 | 75 | resetTotalParticles(numberOfParticles); 76 | 77 | return true; 78 | } 79 | 80 | void ParticleSystem::resetTotalParticles(int numberOfParticles) 81 | { 82 | if (particle_data_.size() < numberOfParticles) 83 | { 84 | particle_data_.resize(numberOfParticles); 85 | } 86 | } 87 | 88 | ParticleSystem::~ParticleSystem() 89 | { 90 | } 91 | 92 | void ParticleSystem::addParticles(int count) 93 | { 94 | if (_paused) 95 | { 96 | return; 97 | } 98 | uint32_t RANDSEED = rand(); 99 | 100 | int start = _particleCount; 101 | _particleCount += count; 102 | 103 | //life 104 | for (int i = start; i < _particleCount; ++i) 105 | { 106 | float theLife = _life + _lifeVar * RANDOM_M11(&RANDSEED); 107 | particle_data_[i].timeToLive = (std::max)(0.0f, theLife); 108 | } 109 | 110 | //position 111 | for (int i = start; i < _particleCount; ++i) 112 | { 113 | particle_data_[i].posx = _sourcePosition.x + _posVar.x * RANDOM_M11(&RANDSEED); 114 | } 115 | 116 | for (int i = start; i < _particleCount; ++i) 117 | { 118 | particle_data_[i].posy = _sourcePosition.y + _posVar.y * RANDOM_M11(&RANDSEED); 119 | } 120 | 121 | //color 122 | #define SET_COLOR(c, b, v) \ 123 | for (int i = start; i < _particleCount; ++i) \ 124 | { \ 125 | particle_data_[i].c = clampf(b + v * RANDOM_M11(&RANDSEED), 0, 1); \ 126 | } 127 | 128 | SET_COLOR(colorR, _startColor.r, _startColorVar.r); 129 | SET_COLOR(colorG, _startColor.g, _startColorVar.g); 130 | SET_COLOR(colorB, _startColor.b, _startColorVar.b); 131 | SET_COLOR(colorA, _startColor.a, _startColorVar.a); 132 | 133 | SET_COLOR(deltaColorR, _endColor.r, _endColorVar.r); 134 | SET_COLOR(deltaColorG, _endColor.g, _endColorVar.g); 135 | SET_COLOR(deltaColorB, _endColor.b, _endColorVar.b); 136 | SET_COLOR(deltaColorA, _endColor.a, _endColorVar.a); 137 | 138 | #define SET_DELTA_COLOR(c, dc) \ 139 | for (int i = start; i < _particleCount; ++i) \ 140 | { \ 141 | particle_data_[i].dc = (particle_data_[i].dc - particle_data_[i].c) / particle_data_[i].timeToLive; \ 142 | } 143 | 144 | SET_DELTA_COLOR(colorR, deltaColorR); 145 | SET_DELTA_COLOR(colorG, deltaColorG); 146 | SET_DELTA_COLOR(colorB, deltaColorB); 147 | SET_DELTA_COLOR(colorA, deltaColorA); 148 | 149 | //size 150 | for (int i = start; i < _particleCount; ++i) 151 | { 152 | particle_data_[i].size = _startSize + _startSizeVar * RANDOM_M11(&RANDSEED); 153 | particle_data_[i].size = (std::max)(0.0f, particle_data_[i].size); 154 | } 155 | 156 | if (_endSize != START_SIZE_EQUAL_TO_END_SIZE) 157 | { 158 | for (int i = start; i < _particleCount; ++i) 159 | { 160 | float endSize = _endSize + _endSizeVar * RANDOM_M11(&RANDSEED); 161 | endSize = (std::max)(0.0f, endSize); 162 | particle_data_[i].deltaSize = (endSize - particle_data_[i].size) / particle_data_[i].timeToLive; 163 | } 164 | } 165 | else 166 | { 167 | for (int i = start; i < _particleCount; ++i) 168 | { 169 | particle_data_[i].deltaSize = 0.0f; 170 | } 171 | } 172 | 173 | // rotation 174 | for (int i = start; i < _particleCount; ++i) 175 | { 176 | particle_data_[i].rotation = _startSpin + _startSpinVar * RANDOM_M11(&RANDSEED); 177 | } 178 | for (int i = start; i < _particleCount; ++i) 179 | { 180 | float endA = _endSpin + _endSpinVar * RANDOM_M11(&RANDSEED); 181 | particle_data_[i].deltaRotation = (endA - particle_data_[i].rotation) / particle_data_[i].timeToLive; 182 | } 183 | 184 | // position 185 | Vec2 pos; 186 | pos.x = x_; 187 | pos.y = y_; 188 | 189 | for (int i = start; i < _particleCount; ++i) 190 | { 191 | particle_data_[i].startPosX = pos.x; 192 | } 193 | for (int i = start; i < _particleCount; ++i) 194 | { 195 | particle_data_[i].startPosY = pos.y; 196 | } 197 | 198 | // Mode Gravity: A 199 | if (_emitterMode == Mode::GRAVITY) 200 | { 201 | 202 | // radial accel 203 | for (int i = start; i < _particleCount; ++i) 204 | { 205 | particle_data_[i].modeA.radialAccel = modeA.radialAccel + modeA.radialAccelVar * RANDOM_M11(&RANDSEED); 206 | } 207 | 208 | // tangential accel 209 | for (int i = start; i < _particleCount; ++i) 210 | { 211 | particle_data_[i].modeA.tangentialAccel = modeA.tangentialAccel + modeA.tangentialAccelVar * RANDOM_M11(&RANDSEED); 212 | } 213 | 214 | // rotation is dir 215 | if (modeA.rotationIsDir) 216 | { 217 | for (int i = start; i < _particleCount; ++i) 218 | { 219 | float a = Deg2Rad(_angle + _angleVar * RANDOM_M11(&RANDSEED)); 220 | Vec2 v(cosf(a), sinf(a)); 221 | float s = modeA.speed + modeA.speedVar * RANDOM_M11(&RANDSEED); 222 | Vec2 dir = v * s; 223 | particle_data_[i].modeA.dirX = dir.x; //v * s ; 224 | particle_data_[i].modeA.dirY = dir.y; 225 | particle_data_[i].rotation = -Rad2Deg(dir.getAngle()); 226 | } 227 | } 228 | else 229 | { 230 | for (int i = start; i < _particleCount; ++i) 231 | { 232 | float a = Deg2Rad(_angle + _angleVar * RANDOM_M11(&RANDSEED)); 233 | Vec2 v(cosf(a), sinf(a)); 234 | float s = modeA.speed + modeA.speedVar * RANDOM_M11(&RANDSEED); 235 | Vec2 dir = v * s; 236 | particle_data_[i].modeA.dirX = dir.x; //v * s ; 237 | particle_data_[i].modeA.dirY = dir.y; 238 | } 239 | } 240 | } 241 | 242 | // Mode Radius: B 243 | else 244 | { 245 | for (int i = start; i < _particleCount; ++i) 246 | { 247 | particle_data_[i].modeB.radius = modeB.startRadius + modeB.startRadiusVar * RANDOM_M11(&RANDSEED); 248 | } 249 | 250 | for (int i = start; i < _particleCount; ++i) 251 | { 252 | particle_data_[i].modeB.angle = Deg2Rad(_angle + _angleVar * RANDOM_M11(&RANDSEED)); 253 | } 254 | 255 | for (int i = start; i < _particleCount; ++i) 256 | { 257 | particle_data_[i].modeB.degreesPerSecond = Deg2Rad(modeB.rotatePerSecond + modeB.rotatePerSecondVar * RANDOM_M11(&RANDSEED)); 258 | } 259 | 260 | if (modeB.endRadius == START_RADIUS_EQUAL_TO_END_RADIUS) 261 | { 262 | for (int i = start; i < _particleCount; ++i) 263 | { 264 | particle_data_[i].modeB.deltaRadius = 0.0f; 265 | } 266 | } 267 | else 268 | { 269 | for (int i = start; i < _particleCount; ++i) 270 | { 271 | float endRadius = modeB.endRadius + modeB.endRadiusVar * RANDOM_M11(&RANDSEED); 272 | particle_data_[i].modeB.deltaRadius = (endRadius - particle_data_[i].modeB.radius) / particle_data_[i].timeToLive; 273 | } 274 | } 275 | } 276 | } 277 | 278 | void ParticleSystem::stopSystem() 279 | { 280 | _isActive = false; 281 | _elapsed = _duration; 282 | _emitCounter = 0; 283 | } 284 | 285 | void ParticleSystem::resetSystem() 286 | { 287 | _isActive = true; 288 | _elapsed = 0; 289 | for (int i = 0; i < _particleCount; ++i) 290 | { 291 | //particle_data_[i].timeToLive = 0.0f; 292 | } 293 | } 294 | 295 | bool ParticleSystem::isFull() 296 | { 297 | return (_particleCount == _totalParticles); 298 | } 299 | 300 | // ParticleSystem - MainLoop 301 | void ParticleSystem::update() 302 | { 303 | float dt = 1.0 / 25; 304 | if (_isActive && _emissionRate) 305 | { 306 | float rate = 1.0f / _emissionRate; 307 | int totalParticles = _totalParticles; 308 | 309 | //issue #1201, prevent bursts of particles, due to too high emitCounter 310 | if (_particleCount < totalParticles) 311 | { 312 | _emitCounter += dt; 313 | if (_emitCounter < 0.f) 314 | { 315 | _emitCounter = 0.f; 316 | } 317 | } 318 | 319 | int emitCount = (std::min)(1.0f * (totalParticles - _particleCount), _emitCounter / rate); 320 | addParticles(emitCount); 321 | _emitCounter -= rate * emitCount; 322 | 323 | _elapsed += dt; 324 | if (_elapsed < 0.f) 325 | { 326 | _elapsed = 0.f; 327 | } 328 | if (_duration != DURATION_INFINITY && _duration < _elapsed) 329 | { 330 | this->stopSystem(); 331 | } 332 | } 333 | 334 | for (int i = 0; i < _particleCount; ++i) 335 | { 336 | particle_data_[i].timeToLive -= dt; 337 | } 338 | 339 | // rebirth 340 | for (int i = 0; i < _particleCount; ++i) 341 | { 342 | if (particle_data_[i].timeToLive <= 0.0f) 343 | { 344 | int j = _particleCount - 1; 345 | //while (j > 0 && particle_data_[i].timeToLive <= 0) 346 | //{ 347 | // _particleCount--; 348 | // j--; 349 | //} 350 | particle_data_[i] = particle_data_[_particleCount - 1]; 351 | --_particleCount; 352 | } 353 | } 354 | 355 | if (_emitterMode == Mode::GRAVITY) 356 | { 357 | for (int i = 0; i < _particleCount; ++i) 358 | { 359 | Pointf tmp, radial = { 0.0f, 0.0f }, tangential; 360 | 361 | // radial acceleration 362 | if (particle_data_[i].posx || particle_data_[i].posy) 363 | { 364 | normalize_point(particle_data_[i].posx, particle_data_[i].posy, &radial); 365 | } 366 | tangential = radial; 367 | radial.x *= particle_data_[i].modeA.radialAccel; 368 | radial.y *= particle_data_[i].modeA.radialAccel; 369 | 370 | // tangential acceleration 371 | std::swap(tangential.x, tangential.y); 372 | tangential.x *= -particle_data_[i].modeA.tangentialAccel; 373 | tangential.y *= particle_data_[i].modeA.tangentialAccel; 374 | 375 | // (gravity + radial + tangential) * dt 376 | tmp.x = radial.x + tangential.x + modeA.gravity.x; 377 | tmp.y = radial.y + tangential.y + modeA.gravity.y; 378 | tmp.x *= dt; 379 | tmp.y *= dt; 380 | 381 | particle_data_[i].modeA.dirX += tmp.x; 382 | particle_data_[i].modeA.dirY += tmp.y; 383 | 384 | // this is cocos2d-x v3.0 385 | // if (_configName.length()>0 && _yCoordFlipped != -1) 386 | 387 | // this is cocos2d-x v3.0 388 | tmp.x = particle_data_[i].modeA.dirX * dt * _yCoordFlipped; 389 | tmp.y = particle_data_[i].modeA.dirY * dt * _yCoordFlipped; 390 | particle_data_[i].posx += tmp.x; 391 | particle_data_[i].posy += tmp.y; 392 | } 393 | } 394 | else 395 | { 396 | for (int i = 0; i < _particleCount; ++i) 397 | { 398 | particle_data_[i].modeB.angle += particle_data_[i].modeB.degreesPerSecond * dt; 399 | particle_data_[i].modeB.radius += particle_data_[i].modeB.deltaRadius * dt; 400 | particle_data_[i].posx = -cosf(particle_data_[i].modeB.angle) * particle_data_[i].modeB.radius; 401 | particle_data_[i].posy = -sinf(particle_data_[i].modeB.angle) * particle_data_[i].modeB.radius * _yCoordFlipped; 402 | } 403 | } 404 | 405 | //color, size, rotation 406 | for (int i = 0; i < _particleCount; ++i) 407 | { 408 | particle_data_[i].colorR += particle_data_[i].deltaColorR * dt; 409 | particle_data_[i].colorG += particle_data_[i].deltaColorG * dt; 410 | particle_data_[i].colorB += particle_data_[i].deltaColorB * dt; 411 | particle_data_[i].colorA += particle_data_[i].deltaColorA * dt; 412 | particle_data_[i].size += (particle_data_[i].deltaSize * dt); 413 | particle_data_[i].size = (std::max)(0.0f, particle_data_[i].size); 414 | particle_data_[i].rotation += particle_data_[i].deltaRotation * dt; 415 | } 416 | } 417 | 418 | // ParticleSystem - Texture protocol 419 | void ParticleSystem::setTexture(SDL_Texture* var) 420 | { 421 | if (_texture != var) 422 | { 423 | _texture = var; 424 | } 425 | } 426 | 427 | void ParticleSystem::draw() 428 | { 429 | if (_texture == nullptr) 430 | { 431 | return; 432 | } 433 | for (int i = 0; i < _particleCount; i++) 434 | { 435 | auto& p = particle_data_[i]; 436 | if (p.size <=0 || p.colorA <= 0) 437 | { 438 | continue; 439 | } 440 | SDL_Rect r = { int(p.posx + p.startPosX - p.size / 2), int(p.posy + p.startPosY - p.size / 2), int(p.size), int(p.size) }; 441 | SDL_Color c = { Uint8(p.colorR * 255), Uint8(p.colorG * 255), Uint8(p.colorB * 255), Uint8(p.colorA * 255) }; 442 | SDL_SetTextureColorMod(_texture, c.r, c.g, c.b); 443 | SDL_SetTextureAlphaMod(_texture, c.a); 444 | SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND); 445 | SDL_RenderCopyEx(_renderer, _texture, nullptr, &r, p.rotation, nullptr, SDL_FLIP_NONE); 446 | } 447 | update(); 448 | } 449 | 450 | SDL_Texture* ParticleSystem::getTexture() 451 | { 452 | return _texture; 453 | } 454 | 455 | // ParticleSystem - Properties of Gravity Mode 456 | void ParticleSystem::setTangentialAccel(float t) 457 | { 458 | modeA.tangentialAccel = t; 459 | } 460 | 461 | float ParticleSystem::getTangentialAccel() const 462 | { 463 | return modeA.tangentialAccel; 464 | } 465 | 466 | void ParticleSystem::setTangentialAccelVar(float t) 467 | { 468 | modeA.tangentialAccelVar = t; 469 | } 470 | 471 | float ParticleSystem::getTangentialAccelVar() const 472 | { 473 | return modeA.tangentialAccelVar; 474 | } 475 | 476 | void ParticleSystem::setRadialAccel(float t) 477 | { 478 | modeA.radialAccel = t; 479 | } 480 | 481 | float ParticleSystem::getRadialAccel() const 482 | { 483 | return modeA.radialAccel; 484 | } 485 | 486 | void ParticleSystem::setRadialAccelVar(float t) 487 | { 488 | modeA.radialAccelVar = t; 489 | } 490 | 491 | float ParticleSystem::getRadialAccelVar() const 492 | { 493 | return modeA.radialAccelVar; 494 | } 495 | 496 | void ParticleSystem::setRotationIsDir(bool t) 497 | { 498 | modeA.rotationIsDir = t; 499 | } 500 | 501 | bool ParticleSystem::getRotationIsDir() const 502 | { 503 | return modeA.rotationIsDir; 504 | } 505 | 506 | void ParticleSystem::setGravity(const Vec2& g) 507 | { 508 | modeA.gravity = g; 509 | } 510 | 511 | const Vec2& ParticleSystem::getGravity() 512 | { 513 | return modeA.gravity; 514 | } 515 | 516 | void ParticleSystem::setSpeed(float speed) 517 | { 518 | modeA.speed = speed; 519 | } 520 | 521 | float ParticleSystem::getSpeed() const 522 | { 523 | return modeA.speed; 524 | } 525 | 526 | void ParticleSystem::setSpeedVar(float speedVar) 527 | { 528 | 529 | modeA.speedVar = speedVar; 530 | } 531 | 532 | float ParticleSystem::getSpeedVar() const 533 | { 534 | 535 | return modeA.speedVar; 536 | } 537 | 538 | // ParticleSystem - Properties of Radius Mode 539 | void ParticleSystem::setStartRadius(float startRadius) 540 | { 541 | modeB.startRadius = startRadius; 542 | } 543 | 544 | float ParticleSystem::getStartRadius() const 545 | { 546 | return modeB.startRadius; 547 | } 548 | 549 | void ParticleSystem::setStartRadiusVar(float startRadiusVar) 550 | { 551 | modeB.startRadiusVar = startRadiusVar; 552 | } 553 | 554 | float ParticleSystem::getStartRadiusVar() const 555 | { 556 | return modeB.startRadiusVar; 557 | } 558 | 559 | void ParticleSystem::setEndRadius(float endRadius) 560 | { 561 | modeB.endRadius = endRadius; 562 | } 563 | 564 | float ParticleSystem::getEndRadius() const 565 | { 566 | return modeB.endRadius; 567 | } 568 | 569 | void ParticleSystem::setEndRadiusVar(float endRadiusVar) 570 | { 571 | modeB.endRadiusVar = endRadiusVar; 572 | } 573 | 574 | float ParticleSystem::getEndRadiusVar() const 575 | { 576 | 577 | return modeB.endRadiusVar; 578 | } 579 | 580 | void ParticleSystem::setRotatePerSecond(float degrees) 581 | { 582 | modeB.rotatePerSecond = degrees; 583 | } 584 | 585 | float ParticleSystem::getRotatePerSecond() const 586 | { 587 | return modeB.rotatePerSecond; 588 | } 589 | 590 | void ParticleSystem::setRotatePerSecondVar(float degrees) 591 | { 592 | modeB.rotatePerSecondVar = degrees; 593 | } 594 | 595 | float ParticleSystem::getRotatePerSecondVar() const 596 | { 597 | return modeB.rotatePerSecondVar; 598 | } 599 | 600 | bool ParticleSystem::isActive() const 601 | { 602 | return _isActive; 603 | } 604 | 605 | int ParticleSystem::getTotalParticles() const 606 | { 607 | return _totalParticles; 608 | } 609 | 610 | void ParticleSystem::setTotalParticles(int var) 611 | { 612 | _totalParticles = var; 613 | } 614 | 615 | bool ParticleSystem::isAutoRemoveOnFinish() const 616 | { 617 | return _isAutoRemoveOnFinish; 618 | } 619 | 620 | void ParticleSystem::setAutoRemoveOnFinish(bool var) 621 | { 622 | _isAutoRemoveOnFinish = var; 623 | } 624 | 625 | ////don't use a transform matrix, this is faster 626 | //void ParticleSystem::setScale(float s) 627 | //{ 628 | // _transformSystemDirty = true; 629 | // Node::setScale(s); 630 | //} 631 | // 632 | //void ParticleSystem::setRotation(float newRotation) 633 | //{ 634 | // _transformSystemDirty = true; 635 | // Node::setRotation(newRotation); 636 | //} 637 | // 638 | //void ParticleSystem::setScaleX(float newScaleX) 639 | //{ 640 | // _transformSystemDirty = true; 641 | // Node::setScaleX(newScaleX); 642 | //} 643 | // 644 | //void ParticleSystem::setScaleY(float newScaleY) 645 | //{ 646 | // _transformSystemDirty = true; 647 | // Node::setScaleY(newScaleY); 648 | //} 649 | 650 | bool ParticleSystem::isPaused() const 651 | { 652 | return _paused; 653 | } 654 | 655 | void ParticleSystem::pauseEmissions() 656 | { 657 | _paused = true; 658 | } 659 | 660 | void ParticleSystem::resumeEmissions() 661 | { 662 | _paused = false; 663 | } 664 | -------------------------------------------------------------------------------- /ParticleSystem.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsty/SDL2-particles/61d25ad9ada567674e62c8e378a328aa83423e74/ParticleSystem.h -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SDL2-particles 2 | 3 | A Particle System for SDL2. 4 | 5 | Modified from that of Cocos2dx. 6 | 7 | It is a part of kys-cpp (). 8 | 9 | ## How to use: 10 | 11 | An example has been supplied in main.cpp, please notice the comments: 12 | 13 | ```c++ 14 | #include "SDL2/SDL.h" 15 | #include "ParticleExample.h" 16 | 17 | int main(int, char* argv[]) 18 | { 19 | SDL_Init(SDL_INIT_VIDEO); 20 | auto win = SDL_CreateWindow("SDL2 Particles", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 768, SDL_WINDOW_OPENGL); 21 | auto ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED); 22 | 23 | auto p = new ParticleExample(); // create a new particle system pointer 24 | p->setRenderer(ren); // set the renderer 25 | p->setPosition(512, 384); // set the position 26 | p->setStyle(ParticleExample::FIRE); // set the example effects 27 | 28 | while (1) 29 | { 30 | SDL_Event e; 31 | SDL_PollEvent(&e); 32 | if (e.type == SDL_KEYUP) 33 | { 34 | int s = (e.key.keysym.sym - SDLK_a + 1); 35 | p->setStyle(ParticleExample::PatticleStyle(s)); // switch the example effects 36 | } 37 | 38 | SDL_RenderClear(ren); 39 | p->draw(); // you have to draw it in each loop 40 | SDL_RenderPresent(ren); 41 | SDL_Delay(10); 42 | } 43 | 44 | SDL_DestroyRenderer(ren); 45 | SDL_DestroyWindow(win); 46 | delete p; // destroy it 47 | 48 | return 0; 49 | } 50 | ``` 51 | 52 | You can press A ~ K to switch the 11 example effects. 53 | 54 | 55 | 56 | ## Effect Examples 57 | 58 | Fire 59 | 60 | ![fire](https://raw.githubusercontent.com/scarsty/SDL2-particles/master/pic/fire.png) 61 | 62 | Snow 63 | 64 | ![snow](https://raw.githubusercontent.com/scarsty/SDL2-particles/master/pic/snow.png) -------------------------------------------------------------------------------- /fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsty/SDL2-particles/61d25ad9ada567674e62c8e378a328aa83423e74/fire.png -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "ParticleExample.h" 2 | #include "SDL2/SDL.h" 3 | 4 | int main(int, char* argv[]) 5 | { 6 | SDL_Init(SDL_INIT_VIDEO); 7 | auto win = SDL_CreateWindow("SDL2 Particles", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 768, SDL_WINDOW_OPENGL); 8 | auto ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED); 9 | 10 | auto p = new ParticleExample(); // create a new particle system pointer 11 | p->setRenderer(ren); // set the renderer 12 | p->setPosition(512, 384); // set the position 13 | p->setStyle(ParticleExample::FIRE); // set the example effects 14 | p->setStartSpin(0); 15 | p->setStartSpinVar(90); 16 | p->setEndSpin(90); 17 | p->setStartSpinVar(90); 18 | 19 | while (1) 20 | { 21 | SDL_Event e; 22 | SDL_PollEvent(&e); 23 | if (e.type == SDL_KEYUP) 24 | { 25 | int s = (e.key.keysym.sym - SDLK_a + 1); 26 | p->setStyle(ParticleExample::PatticleStyle(s)); // switch the example effects 27 | } 28 | if (e.type == SDL_QUIT) 29 | { 30 | break; 31 | } 32 | 33 | SDL_RenderClear(ren); 34 | p->draw(); // you have to draw it in each loop 35 | SDL_RenderPresent(ren); 36 | SDL_Delay(10); 37 | } 38 | 39 | SDL_DestroyRenderer(ren); 40 | SDL_DestroyWindow(win); 41 | delete p; // destroy it 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /pic/fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsty/SDL2-particles/61d25ad9ada567674e62c8e378a328aa83423e74/pic/fire.png -------------------------------------------------------------------------------- /pic/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsty/SDL2-particles/61d25ad9ada567674e62c8e378a328aa83423e74/pic/snow.png --------------------------------------------------------------------------------