Particle Systems – Part 2

Graphics: XNA

Language: C#

Source code: Download

In the previous part of this post I gave the basic introduction of particle systems and a explanation of a particle implementation in XNA. I will continue in this one with the implementation of the particle system itself. I’ll start with a basic example and then move on to a more complex system that I will finally use to make a nice star field effect. You can see the end result in the video below (I recommend seeing it in HD in full-screen to appreciate the effect better):

Star field Particle System from Stilghar on Vimeo.

But let’s start doing something more simple, something like this:

I know, it’s ugly. But we have to start somewhere.

Basic System

We’ll take the particles of our previous example and create a new class to handle them. Just like this:

    public class ParticleEngine_basic
    {
        //A random number generator to add realism
        private Random random;
        //The emitter of the particles
        public Vector2 EmitterLocation { get; set; }
        //The pools of particles handled by the system
        private List<Particle_basic> particles;
        //The texture used for the particles
        private Texture2D texture;

        public ParticleEngine_basic(Texture2D texture, Vector2 location)
        {
            EmitterLocation = location;
            this.texture = texture;
            this.particles = new List<Particle_basic>();
            random = new Random();
        }

        //Method that handles the generation of particles and defines
        //its behaviour
        private Particle_basic GenerateNewParticle()
        {
            //Create the particles at the emitter
            Vector2 position = EmitterLocation;
            //Just a random direction
            Vector2 direction = new Vector2(
                (float)(random.NextDouble()*2-1),
                (float)(random.NextDouble()*2-1));
            // A random life time constrained to a maximum value
            int lifetime = 1 + random.Next(400);
            return new Particle_basic(texture, position,
            direction,lifetime);
        }

        public void Update()
        {
            //Number of particles added to the system every update
            int total = 10;
            for (int i = 0; i < total; i++)
            {
                particles.Add(GenerateNewParticle());
            }

            //We remove the particles that reach their life time
            for (int particle = 0; particle < particles.Count; particle++)
            {
                particles[particle].Update();
                if (particles[particle].lifeTime <= 0)
                {
                    particles.RemoveAt(particle);
                    particle--;
                }
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            //Drawing all the particles of the system
            for (int index = 0; index < particles.Count; index++)
            {
                particles[index].Draw(spriteBatch);
            }

        }
    }

This seems like a loot of code just in one go but if you look at it everything is pretty basic and is well commented. Just as a summary, I have the constructor, an update and a draw method. Besides these usual suspects, I also added a GenerateNewParticle() method. This method is the one that is actually important as is where new particles are created and its behaviour is setup. As you can see it relies in the usage of random numbers to have different particle characteristics. The Update() method just adds some new particles at every pass using this method and removes the ones that have died (reached their life time). Draw() is self explanatory.

Updated Particles

In order to make our star field we need to have some more control over our particles. So, first of all we’ll update them adding more properties to the Particle class:

// The rotation of the particle
public float rotation { get; set; }
// The rotation rate
public float rotationRate { get; set; }
// The color of the particle
public Color color { get; set; }
// The fading of the particle
public float fadeValue { get; set; }
// The fading rate of the particle
// they can dissapear/apper smoothly with this
public float fadeRate { get; set; }
// The size of the particle
public float size { get; set; }
// The size rate of the particle to make them bigger/smaller
// over time
public float sizeRate { get; set; }

With this new properties we’ll now be able to modify the behaviour of the particles over time. It is also needed to update the constructor and the rest of the methods. The Update() method will not need to also take care of updating all these new properties and the Draw() now will have to take them into account. Like this:

        public Particle_advanced(Texture2D texture, Vector2 position, Vector2 direction,
            float rotation, float rotationRate, Color color, float fadeValue, float fadeRate,
            float size, float sizeRate, int lifeTime)
        {
            this.texture = texture;
            this.position = position;
            this.direction = direction;
            this.rotation = rotation;
            this.rotationRate = rotationRate;
            this.color = color;
            this.fadeValue = fadeValue;
            this.fadeRate = fadeRate;
            this.size = size;
            this.lifeTime = lifeTime;
        }

        public void Update()
        {
            lifeTime--;
            position += direction;
            rotation += rotationRate;
            fadeValue += fadeRate;
            size += sizeRate;
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, null, color*fadeValue,
                rotation, new Vector2(0,0), size, SpriteEffects.None, 0f);
        }

Updated particle system

With these new particles we can now upgrade also our basic particle engine to create a star field effect.The only changes that are needed are in the GenerateNewParticles() method of the particle engine. Playing with the rotataion, color, fade and size we can get the effect we are after:

        private Particle_advanced GenerateNewParticle()
        {
            //Create the particles at the emitter and
            //move it around randomly just a bit
            Vector2 position = EmitterLocation + new Vector2(
                    (float)(random.NextDouble() * 10 - 10),
                    (float)(random.NextDouble() * 10 - 10));
            //Just a random direction. Effectively, they
            //go in every direction
            Vector2 direction = new Vector2(
                (float)(random.NextDouble() * 2 - 1),
                (float)(random.NextDouble() * 2 - 1));
            // A random life time constrained to a minimum and maximum value
            int lifeTime = 1000 + random.Next(400);

            // The particles are rotated so that they seem to come
            // from a point in the infinite. No need to rotate them over time
            float rotation = -1*(float)Math.Atan2(direction.X,direction.Y);
            float rotationRate = 0;
            // A color in the blueish tones
            Color color = new Color(0f , (float)random.NextDouble(), 1f);
            // An initial random size and decreasing over time
            float size = (float)random.NextDouble()/4;
            float sizeRate = -0.01f;
            // A 0 fade value to start (so they don't pop in)
            // and an increase over time
            float fadeValue = 0f;
            float fadeRate = 0.001f*(float)random.NextDouble();

            return new Particle_advanced(texture,position, direction,
                rotation, rotationRate,color, fadeValue,
                fadeRate, size, sizeRate, lifeTime);
        }

And with this we’ll obtain our nice looking star field! In this example, I haven’t gone into the performance issues which of course need to be addressed. Also, as it can be seen we have a lot of numbers and properties going around. And we need to recompile the whole thing just to change the value of a property. I’ll try to address these two limitations in the next article. I’ll explain how to modify the particle system to use a pre-instantiated pool of particles and to define the behaviour in an external configuration file that does not need to be compiled (XML). By the way, just playing with the values of the properties you can change the effect in many ways. For example, this has been done changing only the values and using the exact same code:

particlesystem_advance

 

Advertisements

One response to “Particle Systems – Part 2

  1. Pingback: Particle Systems – Part 3 (Unity’s Shuriken) | Stilghar·

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s