# Simple Particle Effects

I was playing around with some particle effects, and decided to write a post about it.

yt. zxN71bGAaSY

This is a particle simulation in C#/XNA using a simplified version of Euler Integration . There’s nothing ground-breaking about this demo, but it is fun to play with, so I decided to write a blog post about it while I wait for my replacement motherboard to arrive.

### Overview

This demo consists of a `Particle` class and the `Game1` class that is generated when making a new XNA project. The `Particle` class holds all of the data for each particle, while the majority of the logic occurs in Game1’s `Update` and `Draw` methods.

The demo allows you to create and destroy particles using the keyboard, and manipulate their forces with the mouse.

### Particle Class

The `Particle` class holds the properties of each particle.

``````public class Particle
{
public Color color;
public Vector2 position;
public Vector2 oldPosition;
public Vector2 velocity;
public float relativeLength;
public float relativeLengthSq;
public float angle;```

```    public Particle(Color color, Vector2 position, Vector2 velocity)
{
this.color = color;
this.position = position;
oldPosition = position;
this.velocity = velocity;
}
}``````

The two most important properties for the particle are `position` and `velocity`. The particle’s velocity is modified each frame by adding forces like gravity, or forces created by mouse input. The particle’s position is modified by adding the particle’s velocity.

The rest of the variables in `Particle` are used for rendering. `color` is the base color used to render the particle. `oldPosition` stores the position of the particle in the previous frame. The `relativeLength` and `relativeLengthSq` variables hold the distance and squared distance between the current and previous position. `angle` is the angle between the current and previous position.

The particle’s previous position is stored in order to draw a line from it to the current position. Instead of drawing an actual line, I just stretch the particle texture using the `relativeLength` variable.

I also want the particle color to change depending on the speed. The `relativeLength` variable is larger the faster the particle is moving, so I could use that as the speed and multiply it by the particle’s `color`. In the end, however, I multiplied the `relativeLengthSq` by the particle’s `color`, so the transition between the base `color` and white is more abrupt.

### Basic Logic

There are three main parts to the logic: initialization (happens once), updating (happens every frame), and drawing (also happens every frame).

#### Initialization

I stored the `Particle` objects in an array in `Game1`. I decided on a maximum amount of particles for the simulation, and initialized all of the `Particle` objects at once. The number of particles in the simulation are changed by modifying a `numActiveParticles` variable, which controls how many particles are updated/drawn.

``````public class Game1 : Microsoft.Xna.Framework.Game
{
public const int MAX_ACTIVE_PARTICLES = 45000;
private int _numActiveParticles;
private Particle[] _particles;```

`    // ...`

```    protected override void Initialize()
{
Random random = new Random();
_particles = new Particle[MAX_ACTIVE_PARTICLES];```

```        for (int i = 0; i < MAX_ACTIVE_PARTICLES; i++)
{
_particles[i] = new Particle(
new Color(0.25f, 0.25f, 1f) * 0.25f,
new Vector2(200f, 200f),
new Vector2(
(float)random.NextDouble(),
(float)random.NextDouble()));
}```

```        base.Initialize();
}
}``````

#### Updating Particles

First, I want to handle input. I want the plus and minus keys to increase and decrease the amount of active particles. To do that, I need the `KeyboardState` . So, I’ll add `KeyboardState _keyState` as a member variable to `Game1`. I’ll also add `KeyboardState _oldKeyState`, so I can differentiate between a key being held down and a key being pressed once.

For now, I only want to apply a gravitational force to the particles. So add a `Vector2 _gravity` member variable to `Game1` . I use `(0, 0.15f)` as the gravitational force.

Now, for the update loop:

``````protected override void Update(GameTime gameTime)
{
// Get keyboard state
_keyState = Keyboard.GetState();```

```    // Modify the number of active particles by either 10 or 100 depending on whether or not shift is pressed
int increment = _keyState.IsKeyDown(Keys.LeftShift) ? 100 : 10;```

```    // Modify the number of active particles
if (_keyState.IsKeyDown(Keys.OemMinus))
_numActiveParticles = Math.Max(0, _numActiveParticles - increment);
if (_keyState.IsKeyDown(Keys.OemPlus))
_numActiveParticles = Math.Min(MAX_ACTIVE_PARTICLES - 1, _numActiveParticles + increment);```

```    for (int i = 0; i < _numActiveParticles; i++)
{
Particle particle = _particles[i];
Vector2 force = Vector2.Zero;    // this will be used later```

```        // Update particle's velocity and position
particle.oldPosition = particle.position;
particle.velocity += force + _gravity;
particle.position += particle.velocity;```

```        // Calculate other properties that will be used to render
Vector2 relative = particle.oldPosition - particle.position;
particle.relativeLengthSq = relative.LengthSquared();
particle.relativeLength = (float)Math.Sqrt(particle.relativeLengthSq);
particle.angle = (float)Math.Atan2(relative.Y, relative.X);
}```

```    // Store the current key state as the old keystate, in preparation for the next Update() call
_oldKeyState = _keyState;```

```    base.Update(gameTime);
}``````

#### Drawing Particles

All the properties necessary for rendering the individual particles were calculated at the end of the `Update` method. The only thing missing is a particle texture, so import a particle texture into your Content project, and load it (in the `LoadContent` method) into a variable called `_particle` . If you want to draw debug text information, you should load a SpriteFont into the `_font` variable and uncomment the `DrawString` calls.

``````protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);```

`    _spriteBatch.Begin();`

```    for (int i = 0; i < _numActiveParticles; i++)
{
Particle particle = _particles[i];```

```        // Select a speed between 0.1f and 1f
float speed = (float)Math.Max(0.1f, (float)Math.Max(particle.relativeLengthSq * 0.05f, 1f));```

```        _spriteBatch.Draw(_particle, particle.position, _particle.Bounds, particle.color * speed, particle.angle, new Vector2(0, 1), new Vector2(particle.relativeLength / 2f, 1f), SpriteEffects.None, 0f);
}```

```    _spriteBatch.DrawString(_font, String.Format("Particle count: {0}", _numActiveParticles), new Vector2(17, 17), Color.Black, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.2f);
_spriteBatch.DrawString(_font, String.Format("Particle count: {0}", _numActiveParticles), new Vector2(16, 16), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.3f);```

`    _spriteBatch.End();`

```    base.Draw(gameTime);
}``````

Now when you compile the program and increase the number of active particles (plus key), you should have something that resembles this:

The particles are just falling off the screen, so I’ll add some boundary conditions. The easiest way to do that is with `Vector2` ’s `Min` and `Max` methods. First, I need to define the boundaries. Add the two member variables to `Game1`:

``````private Vector2 _topLeft;
private Vector2 _bottomRight;``````

Now I set those bounds in the `Initialize` method. The `_topLeft` boundary is inset a little from the corner of the screen at `(64, 64)` . The `_bottomRight` boundary is `(64, 64)` less than the screen’s width and height:

``````_topLeft = new Vector2(64, 64);
_bottomRight = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height) - new Vector2(64, 64);``````

In `Update`, enforce the boundary conditions (after the particle’s position has been calculated) with this line:

``particle.position = Vector2.Min(_bottomRight, Vector2.Max(_topLeft, _particles[i].position));``

Now that the particles are staying within a specified boundary, it’s time to apply some external forces!

### External Forces

I want to add some external forces by using the mouse input. I want the left mouse button to attract particles, and the right mouse button to repel them.

First, I added member variables to `Game1` to track all these states:

``````private MouseState _mouseState;
private Vector2 _mouse;
private bool _mouseDown;
private bool _reverseForce;``````

Then I set the mouse-related variables in the beginning of the `Update` method:

``````_mouseState = Mouse.GetState();
_mouse = new Vector2(_mouseState.X, _mouseState.Y);
_mouseDown = _mouseState.LeftButton == ButtonState.Pressed;
_reverseForce = _mouseState.RightButton == ButtonState.Pressed;``````

Now I can use the mouse position to calculate the forces to apply to each particle. In the for loop in `Update`, calculate the following values:

``````Vector2 relativeMouse = _mouse - particle.position;
float distanceSq = relativeMouse.LengthSquared();``````

Before the particle’s `position` and `velocity` is applied, calculate the force:

``````if (_mouseDown || _reverseForce)
{
// This line is probably horribly incorrect from a physics stand-point, but it works well enough for this demo
force = relativeMouse * (1 / distanceSq) * 100f;
if (_reverseForce)
force *= -1;
}``````

You should now be able to apply forces to the particles by clicking the left and right mouse buttons:

One problem with the code so far, is that the velocity of particles continue to grow even though their positions are being restricted by the boundary. So I decided to use reflection to enforce the boundaries.

### Improving the Boundaries

The equation for a reflected vector is:

``reflection = vector - restitution * dot(normal, vector2) * normal``

`vector` is the vector to be reflected, `normal` is the normal of the surface being hit, and `restitution` is the “bounciness” of the reflection. If you consider the reflection process as a ball hitting a surface, a `restitution` of `2` means that the “ball” will “bounce” back to its original height. I don’t want the particles to bounce that much when they hit the walls, so I allow the restitution to be specified when calling the `reflect` method:

``````private Vector2 reflect(ref Vector2 vector, ref Vector2 normal, float restitution)
{
return vector - restitution * Vector2.Dot(normal, vector) * normal;
}``````

I need to define the normals for each edge. Add the following member variables to `Game1` :

``````private Vector2 _leftEdgeNormal = new Vector2(1, 0);
private Vector2 _rightEdgeNormal = new Vector2(-1, 0);
private Vector2 _topEdgeNormal = new Vector2(0, 1);
private Vector2 _bottomEdgeNormal = new Vector2(0, -1);``````

Every time a particle is updated, I need to store its new position and velocity in temporary variables that can be corrected if necessary. I just call those `newPosition` and `newVelocity`.

I need to check which boundaries the new position is violating, and modify the velocity using the `reflect` method. After the boundary check, the particle’s `position` is updated using the `newVelocity` variable:

``````newVelocity = particle.velocity + force + _gravity;
newPosition = particle.position + newVelocity;```

```// If the new position is crossing a boundary, reflect the velocity against the normal of that edge.
if (newPosition.X < _topLeft.X)
{
newVelocity = reflect(ref newVelocity, ref _leftEdgeNormal, 1.1f);
}
else if (newPosition.X > _bottomRight.X)
{
newVelocity = reflect(ref newVelocity, ref _rightEdgeNormal, 1.1f);
}
if (newPosition.Y < _topLeft.Y)
{
newVelocity = reflect(ref newVelocity, ref _topEdgeNormal, 1.1f);
}
else if (newPosition.Y > _bottomRight.Y)
{
newVelocity = reflect(ref newVelocity, ref _bottomEdgeNormal, 1.1f);
}```

```// Update the particle
particle.oldPosition = particle.position;
particle.velocity = newVelocity;
particle.position += particle.velocity;```

```// Sometimes particles hitting corners can get stuck past boundaries, so I keep this line to enforce the boundary in that case
particle.position = Vector2.Min(_bottomRight, Vector2.Max(_topLeft, _particles[i].position));``````

That’s everything! If I left anything out or if you have any questions, feel free to contact me

Full source code: ParticleEffects.zip