Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
100 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Sample Usage of a Particle System

Ok, so let's define a particle system to use! A declaration would look like the following,

ParticleGroup<1000, 
  CompletePolicy<Particle, ColorInitializer<Particle>,
                 SizeInitializer<Particle>, VelocityInitializer<Particle>,
                 LifeInitializer<Particle>, NullPolicy<Particle> >,
  CompletePolicy<Particle, ColorAction<Particle>, SizeAction<Particle>,
                 GravityAction<Particle>, LifeAction<Particle>,
                 MoveAction<Particle> >, Particle > d_ParticleGroup;

Notice the NullPolicy, which is simply an empty policy which does nothing. Remember once again that we hinted to the compiler to have those function calls inlined, thus a NullPolicy would generate no extra overhead. So to initialize the system, for example, we simply do the following.

d_ParticleGroup.d_InitializePolicy.d_LifePolicy.SetLifeRange(10, 100);
d_ParticleGroup.d_InitializePolicy.d_SizePolicy.d_szSize =
    Size3D (0.025f, 0.025f, 0.025f);
…
d_ParticleGroup.d_ActionPolicy.d_LifePolicy.d_nLife = 1;
d_ParticleGroup.d_ActionPolicy.d_VelocityPolicy.d_vGravity =
    Vector3D (0.0f, -0.0005f, 0.0f);

And so on for the others. And to emit particles,

d_ParticleGroup.Emit(100, Point3D(0.0f, 0.0f, 0.0f));

Processing them,

d_ParticleGroup.Update();

Combining Policies

The original policy design work well, until the point where you might have too many action effects you require, and too little template parameters to work with. For example, you want a gravitational pull as well as a wind action, and you are unable to 'free up' the other policies, as all are essential. The solution here is to use a CompositePolicy. A composite policy is simply a policy itself, and it merges two policies into one. It follows the same rules and workings of a policy.

template <class ParticleType, class Policy1, class Policy2>
class CompositePolicy : public Policy1, public Policy2 {
public : 
  inline void PrepareAction() throw() {
    Policy1::PrepareAction();
    Policy2::PrepareAction();
  }
  inline void operator()(ParticleType& m_Particle) const throw() {
    Policy1::operator()(m_Particle);
    Policy2::operator()(m_Particle);
  }
};  //  end of class CompositePolicy

With a composite policy, you can actually nest them and merge endless possible policies as one. The only drawback here is the possible name collision of any data members in each policy.

Now with the new additional policy, let's add Wind, Gravity, as well as a retracting action to the particle system!

ParticleGroup<1000, 
  CompletePolicy<Particle, ColorInitializer<Particle>, SizeInitializer<Particle>,
                 VelocityInitializer<Particle>, LifeInitializer<Particle>, NullPolicy<Particle> >,
  CompletePolicy<Particle, ColorAction<Particle>, SizeAction<Particle>, 
CompositePolicy<Particle, RetractAction<Particle>, 
      CompositePolicy<Particle, 
        GravityAction<Particle>, WindAction<Particle> > >,
  LifeAction<Particle>, MoveAction<Particle> >,
Particle > d_ParticleGroup;

We can access the gravitational pull factors, retracting, as well as wind force all under the same VelocityPolicy.

d_ParticleGroup.d_ActionPolicy.d_VelocityPolicy.d_vGravity = Vector3D (0.0f, -0.0005f, 0.0f);
d_ParticleGroup.d_ActionPolicy.d_VelocityPolicy.d_vWind = Vector3D(-0.005f, 0.0f, 0.0f);
d_ParticleGroup.d_ActionPolicy.d_VelocityPolicy.d_dwRetractCounter = 50;

One could declare Policy1 and Policy2 as data members of CompositePolicy, but it doesn't scale well for multiple nested policies. Imagine having to write

d_ParticleGroup.d_ActionPolicy.d_Policy1.d_Policy2.d_VelocityPolicy.d_vWind =
    Vector3D(-0.005f, 0.0f, 0.0f);

Now isn't that ugly?

Conclusion

With policies, you can mix and match different effects into a particle system, customizing it for each individual scenario, and yet have the best performance. The only drawback would be the following a fixed naming of data members of a particle, as well as watching out for possible name collision when using CompositePolicy to merge multiple policies.

Feel free to contact me via email(onedotonly@hotmail.com), or look for _dot_ on #gamedev. I'll be happy to answer questions, discuss problems, and merely hear about how you're using the technique and how it's working for you.

Acknowledgements

My many thanks to those on #gamedev who helped reviewed my article, as well as muer for introducing me to the Modern C++ Design book.

Additional Resources

Modern C++ Design, by Andrei Alexandrescu

Advanced Particle Systems by John van der Burg

Particle System API by David McAllister

Trent Polack's: Game Tutorial #03

NeHe Productions: OpenGL Article #06




Contents
  Introduction
  Particle System, a Brief Design
  Defining the Initialization Policy and Action Policy
  Sample Usage of a Particle System

  Printable version
  Discuss this article