2D Particles in XNA – Part 1 (of 3)

When I showed my game *cough* Particle System*cough* to my classmates, some of them asked me how the particle system worked. I told them i worked till 3AM the previous weekend, but there’s a little more to it than staying up all night. That’s why I thought I should write an article about it.

In this article, I’ll show you how to create a simple particle system where the particles don’t obey the laws of physics. Maybe I’ll write another article about that in the future.

People that aren’t familiar with C# + XNA, but with an other graphics engine/API/language (for example: Direct3D 9 with C++)  should be able to follow this as well.

This article assumes you have a basic understanding of C# and XNA but understanding in other languages (+ API/engine combos) suitable for game development should be able to follow this as well.

Before we dive in the code, let’s examine the particle system first.

A particle system is a collection of… particles. So what’s a particle?

A particle consists of a simple sprite (I call it a particle base, but you can call it whatever you want) like this:

My particle sprite

I took a screenshot of the image in Photoshop so you can see the  alpha channel. As you can see it’s a white circle that gets more and more transparent as it goes to the edge.

I’ve chosen for the color white, so that I can easily change the color of the sprite in the application by multiplying a color (or adding a mask depending on your engine/API)

Example: White(1.0f, 1.0f, 1.0f) * Red(1.0f, 0, 0) = (1.0f*1.0f, 1.0f*0, 1.0f*0) = (1,0f, 0, 0) = Red

When multiplying, adding, subtracting colors, just multiply/add/subtract the components separately.

Since every particle should have a different position, we need to make a class that can represent the particle. So let’s define a part of the Particle class.

class Particle
{
    Texture2D ParticleBase;
    Vector2 Position;
    Vector2 Direction;
    float Radius;
    float Color;
    float Life;    // Life left
    public Particle(Texture2D ParticleBase, Vector2 Position, Vector2 Direction,
                        float Radius, float Color, float Life)
    {
        // Store the parameters in the member variables.
    }

    // dt is the number of seconds passed since the last update (delta t)
    public bool Update(float dt) // Why a bool return value?
    {
        this.Position += this.Direction * dt;
        this.Life -= dt;
        if(this.Life > 0)
        {
            return true;
        }
        return false;
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        // Draw the sprite with the right scale on the right position
    }
}

This should be enough to draw a circle that can move in a certain direction and disappear after its life has expired. Of course you’ll want more than one or two of these particles. To get a nice effect, we’ll need several hundreds to thousands of particles. In order to manage all these objects, we’ll need to create a class that does just that.

Administration and Containers/Collections

Say hello to the emitter class. This is a class that can create particles, store them, update them (call their update method), draw them (call their draw method) and eventually delete them. And when a particle gets deleted, we’ll have some room to create a new particle in its place.

We’ll have to store the particle objects in a certain data structure. The question is, which one?

First, we have the good old array. You could make an array of particles, when the life of a particle expires, you could reinitialize the particle, and in that way, you can have an easy management. But maybe, you don’t want to spawn the new particle at exactly the same time as you deleted the old one (with an expired life). So you’ll need to keep an administration of the empty spaces of the array so you can access them later. Also, when you decide to change your emitter properties after creation (for example to create even more particles) You’ll need to resize the arrays.

As you can see, there is some administrative work involved, and we’d (or I’d) rather do more exciting stuff than writing some administrative code. Especially when there are standard template classes (containers/collections) not only in C# , but in almost every popular language (STL for C++ for example) that help us do this easier. If you don’t know what a collection is, here is some quick info: It contains and manages(sorting, adding, removing and stuff) data and can work with almost any type of object. So you can say List to create a list of integers, but also List to make a list of objects of your custom class. Of course there are some limitations. For example sorting can’t be done with every class (How would you sort SpriteBatches?)

The Linked List

We have the List<>  (template) class, which can be roughly described as an array that can be resized. And we have the LinkedList<> class which makes deleting elements in the middle of the list a breeze (you don’t get an empty place in the middle, the two loose ends are linked together seamlessly. In order to use List<> and LinkedList<> add a line with:

using System.Collections.Generic;

A drawback of the LinkedList<> class is that you can’t directly access an element in the middle like in an array with the “[]” operators, you’ll need to “travel” all the way from the beginning or from the end to that element (node) to get access to it. However, you can insert a node into the middle of a linked list (which would be a pain to do in an array). Anyway, the drawback of the linked list isn’t that important to us, because we won’t be needing random access anyway, we’ll want to access every particle (from the first node to the last) and call their update and draw methods and delete them when their life has expired (see return value of Particle.Update())

Also, you don’t have to specify the size of the linked list, because you can reserve the space of every node separately when it is needed.

Let’s go trough the structure of our emitter class:

public class Emitter
{
    Texture2D ParticleBase;
    public int Budget;    // Max number of active particles.
    float NextSpawnIn;    // Next particle creation (spawn) in seconds.
    float SecPassed;      // Seconds passed since last spawn.
    LinkedList<Particle> ActiveParticles;
    Random random;        // Always a good idea to add some noise.

    // TODO:
    // Other variables needed when you generate a particle (color, size, direction...)

    Emitter(variables that the emitter needs to create particles)
    {
        ActiveParticles = new LinkedList<Particle>();    // A linked list also needs to be initialized.
    }

    public void Update(float dt)
    {
        // TODO: Create particle if it's needed using ActiveParticles.AddLast(new Particle());

        LinkedListNode<Particle> node = ActiveParticles.First;
        while (node != null)
        {
            bool isAlive = node.Value.Update(dt);
            node = node.Next;
            if (!isAlive)
            {
                if (node == null)
                {
                    ActiveParticles.RemoveLast();
                }
                else
                {
                    ActiveParticles.Remove(node.Previous);
                }
            }
        }
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        LinkedListNode<Particle> node = ActiveParticles.First;
        while (node != null)
        {
            node.Value.Draw(spriteBatch, Scale, Offset);
            node = node.Next;
        }
    }
}

As you can see, the code is incomplete (so is the code of the Particle class by the way) Don’t worry, there will be a download of the complete source in a later article when all of the aspects of the particle systen are covered.

First, let’s examine the usage of the LinkedList, because that’s probably new to some of you. We add new elements (nodes) to the list using the methods AddLast() or AddFirst() (we use AddLast). LinkedList<> has lots of other methods, you can see them at the MSDN page.

To remove nodes, we use Remove() or RemoveLast().

To access the LinkedList, we need to use something called a LinkedListNode<> (C++ users should be familiar to the term iterator) that will travel trough the list.

We create and set its position to the first element:

LinkedListNode<Particle> node = ActiveParticles.First;

We access the value it’s pointing at (so node.Value is of the type Particle):

bool isAlive = node.Value.Update(dt);

And we also move it to the next position:

node = node.Next;

As you can see node.Next gives us a new object with the same type (LinkedListNode). That means, we can do things like this:

Particle someparticle = node.Next.Next.Next.Value;

When you want to remove a element, you can use the node to point which one you want to delete, however, when you delete the element where your node was pointing at, your node will become invalid. In order to keep a valid node for further use, you could do this:

// How to delete the 7th element while keeping the node "alive"
LinkedListNode<Particle> node = ActiveParticles.First;
node = node.Next.Next.Next.Next.Next.Next;   // This node points to the 7th element.
node = node.Next;   // Make the node point to the element after that one (8th one)
ActiveParticles.Remove(node.Previous);    // Then remove the Previous (7th) element.

One more thing to be careful about is when the node points to the last element in the list and you ask for the next node (node = node.Next)
This will make the node to point to null (node==null) So be sure to check this to see whether you’re at the last node or not. (this also is true for the first element when node.Previous is used)

Enough about the administration, let’s get back to the particle system.

What more?

The Emitter class also needs to create new particles. To do so, use the AddLast method of the LinkedList and call the Particle constructor (new Particle(parameters) ) What you pass in the parameters is up to you.

What I did was define two sizes, two life lengths, two directions and so on in the Emitter, and let the method choose (with the help of a random number) a value between those two. So I would say the scale of the particles should be between 10 and 20 (in this case pixels) and it would choose a random number between those two.

With scale and life, it looks very simple (random.Next(10,20)), but you can also do this with colors and directions. I’ll tell more about these in a later section.

All this noise (randomness) makes your particle systems effects more interesting. In Particle Pong, I added noise to the seconds per spawn (spawn rate), spawn direction, life, scale, end scale, start color, end color, start speed and end speed. You can add more if you can think of them, I just thought of these properties after a little brainstorm.

I’ll try to wrap up this article, because it’s getting a bit too long (we’ll continue in a second part) but there is one thing I need to mention:

All the Emitters will be grouped into a objects of the ParticleSystem class. It isn’t necessary, but it keeps your code clean, and I’ve found that some more complex animation effects requiring multiple emitters can benefit of this grouping, especially because the position of the emitters is relative to the ParticleSysten object you can move a group of emitters more easily.

Next part: Part 2

At the end, I’ll give you a complete working example of a particle effect with source code that you should understand after reading these articles.

Thanks for reading folks, please post comments, questions and/or corrections. I’m not an authority on these things, just a student trying to share his thoughts.