A Particle System is a graphics term for something that simulates a natural system like smoke, fire, rain or sparks (or even flocks of birds). Basically something that can be broken in to small pieces: Particles.
Taking the example from the class demo video I did, the fire effect is made up of a large number of circles. Each circle starts at a specific point on the screen. Each circle is given a random color in the orange/red range. Each circle is given a random direction to move in within a specific range of directions. Each circle has a speed. And each circle has a lifetime.
The fact of the circle or particle “lifetime” points to the “system” part of a Particle System. A particle system controls the creation *and* destruction of the particles. In this case, the lifetime of a particle keeps track of how long the particle stays on screen before it is done. If the particles didn’t have lifetimes, then the stream of fire particles would be endless which wouldn’t have the visual effect I want. Also, quickly there would be too many particles to draw efficiently. The system would visually slow down or there wouldn’t be enough computer power to run it in real time.
Here are the steps that this particle system goes through each time through the draw loop:
- Decide if a particle should be created. Randomly decide to create one or more particles.
- Create the particles, randomly choosing the particle attributes (such as size, color, speed).
- Store information about any created particles in a series of array variables.
- Go through the arrays, drawing and updating the particles on screen.
- Decrease the lifetime of all particles
- If any particles lifetime has reached 0, then remove those particles from the system
Here are some details about the above steps.
Everything about the particles are stored in arrays and they work well for this. Let’s say I decide my system will have at most 200 particles at once. I create arrays that can hold 200 elements and use them to store all of the information about the particles. I have an array for all of the X positions of the particles. Another array for all of the Y positions. I have a separate array for each of:
- X position
- Y position
- X speed
- Y speed
- Particle Lifetime
- Particle Red Value
- Particle Green Value
- Particle Blue Value
- Particle Size (assuming a circle, so just need 1 number)
I needed to start out with the arrays empty and already set to hold 200 elements so I loop through each array and push zeros into them.
Then you need to keep track of which particles are “active”. In the beginning there are no particles being displayed. Then a particle is created and there is one particle. Later there are more. Then some exceed their lifetime and there are less. This means that within your arrays of 200 elements, not all of those particles are active at once. How do we keep track of that?
I had another array to hold whether a particle was active or not. This “active” array also has 200 elements and again starts out with everything being 0. If any element in the active array is a 1, that means that particle is active.
When I say “that particle”, it is VERY important to understand that in this system, all of the data about a particle is spread across multiple arrays. But the index into the array gives you all of the data about that particle across all arrays. So particle 0 will be the 0-th element in all of the arrays. Particle 1 will be the first element in all of the arrays.
To create a particle, we first look in the active array to find an available particle. An available particle has it’s element set to 0 in the active array. When we find an available particle, store its array index and set that array element to 1 in the active array. Then use that array index to set all of the corresponding values in the other arrays.
Create a particle steps:
- Find an available particle slot. Loop through the active array and stop when you find the first element that is 0. Set that element to 1 in the active array. Use the index of that array element (active index) to fill the rest of the arrays.
- Randomly choose values for the particle and store them in corresponding positions in the other arrays. For example, randomly choose an X position and store it in the X position array at location “active index”. Also choose a random particle lifetime.
That is it, basically.
Removing a particle happens when a particle’s lifetime is 0. So each time through the draw loop, go through the lifetime array from start to finish and reduce by 1 the lifetime of any elements that are not 0. And for any elements that become 0 in the lifetime array, ALSO set the same element in the active array to 0.
The active array lets you know what particles are active. That may seem obvious from the name however we use this to know which elements to look at when drawing to screen. Creating particles updates the active array as does removing particles. Then, when drawing to screen, we only care about elements in the active array set to 1.
To draw everything:
- Scan the active array from start to end. For any elements that are 1, do the following:
- Draw the particles using information from all of the other arrays with the same corresponding index.
- If we are at the 5th position of the active array and it is set to 1, take the 5th X position and the 5th Y position and draw something there with a size and color given by the 5th size, r, g, and b values from those arrays.
- Also, don’t forget to update the positions using the speed values you stored in the X and Y speed arrays.
You can have additional attributes for particles that you may think of. Whatever you want to store that you need to draw everything.