The three constructors are easy to understand. The GenerateParticle() function will be used when a new particle is created, whether it's a completely new particle, or when a particle dies and we wish to replace it with a new one. TheUpdate() will be used to update the particles in the system. Update() will need to decide if and when to create new particles. And last, Draw() will be used to display the particle system on a given Graphics object.
///<SUMMARY>
/// Generate a single particle in the system.
/// This function is used when particles
/// are first created, and when they are regenerated
///</SUMMARY>
///<RETURNS>New particle</RETURNS>
protectedoverride Particle GenerateParticle()
{
// Generate random direction & speed for new particle
// In a fountain, particles move almost straight up
float rndX = 0.5f * ((float)m_rand.NextDouble() - 0.4f);
float rndY = -1 - 1 * (float)m_rand.NextDouble();
float rndZ = 2 * ((float)m_rand.NextDouble() - 0.4f);
// Create new particle at system's starting position
Particle part = new Particle(m_Position,
// With generated direction and speed
new Vector(rndX, rndY, rndZ),
// And a random starting life
m_rand.Next(50));
// Return newly created particle
return part;
}
///<SUMMARY>
/// Update all the particles in the system
///</SUMMARY>
///<RETURNS>False - if there are no more particles in system
/// True - otherwise</RETURNS>
publicoverridebool Update()
{
Particle part;
// Get number of particles in the system
int count = m_Particles.Count;
// For each particle
for (int i=0; i < count; i++)
{
// Get particle from list
part = (Particle)m_Particles[i];
// Update particle and check age
if ((!part.Update()) || (part.Life > 150))
{
// Remove old particles
m_Particles.RemoveAt(i);
// Update counter and index
i--;
count = m_Particles.Count;
}
}
// If there aren't enough particles
if(m_Particles.Count < DEFAULT_NUM_PARTICLES)
// Add another particles
m_Particles.Add(GenerateParticle());
// Always return true, since system is regenerating
returntrue;
}
}
}
2 basic particle systems
Now that we've seen the basic interface that we need to implement, we need to start implementing particle systems. Two of the more basic systems are an explosion and a fountain. I'll demonstrate them here.
Explosion
In an explosion, particles just fly everywhere. This is quite easy to implement - we just set all the particles to start at the center of the system, and move to a random direction, with a random speed. Gravity will take care of everything else.
Collapse | Copy Code
using System;
namespace Particles
{
///<SUMMARY>
/// Summary description for Explosion.
///</SUMMARY>
publicclass PSExplosion : ParticlesSystem
{
privatestaticreadonlyint DEFAULT_NUM_PARTICLES = 150;
// Random numbers generator
private Random m_rand = new Random();
///<SUMMARY>
/// Default constructor
///</SUMMARY>
public PSExplosion() : this(Vector.Zero, Color.Black)
{ }
///<SUMMARY>
/// Constructor
///</SUMMARY>
///<PARAMname="pos">Starting position of system</PARAM>
public PSExplosion(Vector pos) : this(pos, Color.Black)
{ }
///<SUMMARY>
/// Constructor
///</SUMMARY>
///<PARAMname="pos">Starting position of system</PARAM>
///<PARAMname="col">Color of the particles in the system</PARAM>
public PSExplosion(Vector pos, Color col)
{
// Set system's position at given position
m_Position = pos;
// Set system color to given color
m_Color = col;
// Create all the particles in the system
for (int i = 0; i < DEFAULT_NUM_PARTICLES; i++)
{
// Create particle, and add it to the list of particles
m_Particles.Add(GenerateParticle());
}
}
///<SUMMARY>
/// Update all the particles in the system
///</SUMMARY>
///<RETURNS>False - if there are no more particles in system
/// True - otherwise</RETURNS>
publicoverridebool Update()
{
Particle part;
// Get number of particles in the system
int count = m_Particles.Count;
// For each particle
for (int i=0; i < count; i++)
{
// Get particle from list
part = (Particle)m_Particles[i];
// Update particle and check age
if ((!part.Update()) || (part.Life > 150))
{
// Remove old particles
m_Particles.RemoveAt(i);
// Update counter and index
i--;
count = m_Particles.Count;
}
}
// If there are no more particles in the system
if (m_Particles.Count <= 0)
returnfalse;
returntrue;
}
///<SUMMARY>
/// Generate a single particle in the system.
/// This function is used when particles
/// are first created, and when they are regenerated
///</SUMMARY>
///<RETURNS>New particle</RETURNS>
protectedoverride Particle GenerateParticle()
{
// Generate random direction & speed for new particle
float rndX = 2 * ((float)m_rand.NextDouble() - 0.5f);
float rndY = 2 * ((float)m_rand.NextDouble() - 0.5f);
float rndZ = 2 * ((float)m_rand.NextDouble() - 0.5f);
// Create new particle at system's starting position
Particle part = new Particle(m_Position,
// With generated direction and speed
new Vector(rndX, rndY, rndZ),
// And a random starting life
m_rand.Next(50));
// Return newly created particle
return part;
}
}
}
In this example, we've created all the particles when the system was created. We've placed them all at exactly the starting point of the system, although for a more realistic look, we might have added a little bit of randomness there too. Each new particle is given a random age - this way the particles don’t die all at the same time. We've also decided to kill particles that are older than 150. We could have chosen another criteria, such as to kill particles only when they leave the display view, or they bumped into something.
Fountain
The fountain example is given here due to two reasons. First, the fountain regenerates particles that die, in order to continue "fountaining" or whatever else fountains do. Secondly, not all the particles are created at once - we first create a few particles, and as time goes on, we add more and more particles to the system.
Collapse | Copy Code
using System;
namespace Particles
{
///<SUMMARY>
/// Summary description for Firework.
///</SUMMARY>
publicclass PSFountain : ParticlesSystem
{
privatestaticreadonlyint DEFAULT_NUM_PARTICLES = 250;
// Random numbers generator
private Random m_rand = new Random();
///<SUMMARY>
/// Default constructor
///</SUMMARY>
public PSFountain() : this(Vector.Zero, Color.Black)
{ }
///<SUMMARY>
/// Constructor
///</SUMMARY>
///<PARAMname="pos">Starting position of system</PARAM>
public PSFountain(Vector pos) : this(pos, Color.Black)
{ }
///<SUMMARY>
/// Constructor
///</SUMMARY>
///<PARAMname="pos">Starting position of system</PARAM>
///<PARAMname="col">Color of the particles in the system</PARAM>
public PSFountain(Vector pos, Color col)
{
// Mark that this system regenerates particles
m_Regenerate = true;
// Set system's position at given position
m_Position = pos;
// Set system color to given color
m_Color = col;
// Create ONLY 5 particles
for (int i = 0; i < 5; i++)
{
// Create particle, and add it to the list of particles
m_Particles.Add(GenerateParticle());
}
}