In this section, we add to the project the emitter, which will create particles at a specified rate.
The example is based on the 03-Particles/01-SingleParticle
project, implemented in the previous section. We implement the emitter right inside the testApp
class. In the class declaration, replace the following line with declaration of a single particle Particle p;
with an array of particles:
vector<Particle> p; //Particles
We will delete inactive particles from any parts of the p
array. So for computational efficiency, it is preferable to use the deque
class instead of vector
. But for simplicity, in this example, we use vector
. It works fast enough for our purposes in the example.
See usage of deque
in the Radial slit-scan example section in Chapter 5, Working with Videos.
Next, add the declaration of the parameter bornRate
and the supplementary variable bornCount
:
float bornRate; //Particles born rate per second float bornCount; //Integrated number of particles to born
The bornRate
parameter sets the number of particles that should be born in one second. If its value is small, the particles should not be born with each testApp::update()
calling, so we need a method of detecting when we should emit new particles. Such a method is using the float variable bornCount
, which accumulates the number of particles that would be born. When it becomes greater than 1.0, we emit the int( bornCount )
particles.
To initialize the values bornRate
and bornCount
, add the following lines to the testApp::setup()
function:
bornRate = 1000; bornCount = 0;
The main part of the modification needed for the emitter implementation is in the testApp::update()
function. It's the beginning that computes dt
that remains untouched from the previous project. Then it deletes the inactive particles from the p
array, gives birth to new particles depending on the bornRate
value parameter, and finally updates all the particles:
void testApp::update(){ //Compute dt float time = ofGetElapsedTimef(); float dt = ofClamp( time - time0, 0, 0.1 ); time0 = time; //Delete inactive particles int i=0; while (i < p.size()) { if ( !p[i].live ) { p.erase( p.begin() + i ); } else { i++; } } //Born new particles bornCount += dt * bornRate; //Update bornCount value if ( bornCount >= 1 ) { //It's time to born particle(s) int bornN = int( bornCount );//How many born bornCount -= bornN; //Correct bornCount value for (int i=0; i<bornN; i++) { Particle newP; newP.setup(); //Start a new particle p.push_back( newP ); //Add this particle to array } } //Update the particles for (int i=0; i<p.size(); i++) { p[i].update( dt ); } }
Finally, in testApp::draw()
, you will find the ensuing lines:
//Draw the particle ofFill(); p.draw();
Replace the preceding lines with the following lines:
//Draw the particles ofFill(); for (int i=0; i<p.size(); i++) { p[i].draw(); }
The project is ready.
Run it, and you will see a beautiful and vivid picture made by many particles flying in curvilinear trajectories and leaving the trails, as shown in the following screenshot:
Now we add a couple of new control parameters for extending the behavior of the particle system.