Over a million developers have joined DZone.

Creating a Simple Particle Effect With XNA For WP7

· Mobile Zone

Visually compose APIs with easy-to-use tooling. Learn how IBM API Connect provides near-universal access to data and services both on-premises and in the cloud, brought to you in partnership with IBM.

Creating a particle effect is just too much fun without sharing it. The objective was to create a simple spark-like particle effect. We will render each spark as a small line that gets transparent with time. Some basic physics will be involved, but I will keep it simple. The final result is seen on the image below. You can download the source code here: wp7.particles (SkyDrive, 26 kB). Please note that the default orientation for this sample is landscape.

First we must decide how to represent the rendering data and then initialize our basic effect. Since we are rendering sparks as lines and we only need position and color, we can use a built in class named VertexPositionColor. Each line consists of two points and we will render all particles in one try. Put the following code in the Initialize method:

// the declaration describes input vertex data
vertexDeclaration = new VertexDeclaration(new VertexElement[]
        new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
        new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0)
basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.VertexColorEnabled = true;
basicEffect.World = Matrix.Identity;
// make sure that we render inside (800x480) rectangle
// where (0,0) is the upper left corner, and (800, 480) is the lower right corner
basicEffect.View = Matrix.CreateScale(1, -1, 1) * Matrix.CreateTranslation(-GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2, 0);
// entire area is rendered flat
basicEffect.Projection = Matrix.CreateOrthographic(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 10);

The code is straightforward for those who have dealt with 3D graphics before. For those who are new to the 3D graphics, we need to setup matrices that describe how data is transformed from 3D coordinates to the screen coordinates. The last three lines in the code snippet above ensure that we can use the following drawing rectangle: [0, 800] x [0, 480] similar to the sprite batch.

Next stop is defining a particle. Particle needs to know where it is in the world (position vector), where it is headed (direction vector), how long it will live (remaining lifetime) and what was the original life span when it was created. The code for the class is given in the snippet below.

class Particle
    public Vector3 pos, dir;
    public double life;
    public double span;

Our update method will do most of the hard work. It will consist of three parts:

  1. Update each particle
  2. Remove dead particles (whose lifetime is less or equal to zero or if they are off screen)
  3. If there are less than a fixed number of particles, create new ones randomly

First update life and position for the current particle. Also, apply gravitational force on the particle, this will make sparks fall realistically. The following code goes into the Update method:

foreach (var particle in _particles)
    particle.life -= gameTime.ElapsedGameTime.TotalMilliseconds;
    // very precise constant for gravity
    particle.dir += new Vector3(0,
                                9.81f * (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f,
    particle.pos += particle.dir;

Next step is to remove dead particles. If only we have RemoveAll function…

_particles = _particles.Where(item => item.life >= 0 && item.pos.Y <= graphics.GraphicsDevice.Viewport.Height).ToList();

Finally, randomly create particles if there are to little particles on screen.

if (_particles.Count() > 1000)
for (int i = 0; i < _random.Next(20, 100); ++i)
    // live from 2 seconds up to 4
    var lifetime = _random.Next(2000, 4000);
    _particles.Add(new Particle()
        life = lifetime,
        span = lifetime,
        // initial position at the bottom center
        pos = new Vector3(graphics.GraphicsDevice.Viewport.Width / 2,
        // they go up and randomly left-right, also, ignore Z axis
        dir = new Vector3((float)_random.NextDouble() * 5 - 2.5f,
                          -12 - (float)_random.NextDouble() * 4,

 Sheesh, that was a lot of code. Now onto the rendering part. Render each particle as a small line, starting from its position and back along the direction vector. The following code goes into the Draw method:

foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
    var data = new List<VertexPositionColor>(_particles.Count * 2);
    foreach (var particle in _particles)
        var color = Color.FromNonPremultiplied(224, 53, 27, (int)(255f * (particle.life / particle.span)));
        data.Add(new VertexPositionColor(particle.pos, color));
        data.Add(new VertexPositionColor(particle.pos - particle.dir, color));
    GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, data.ToArray(), 0, _particles.Count);

The Mobile Zone is brought to you in partnership with Strongloop and IBM.  Visually compose APIs with easy-to-use tooling. Learn how IBM API Connect provides near-universal access to data and services both on-premises and in the cloud.


Published at DZone with permission of Toni Petrina, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}