After doing some more tuning on the grappling hook, I decided to take a break and work on a particle system implementation.

To handle various types of particle effects, I made a generic ParticleSystem class, where you can specify a particle type for the system to handle when creating it, along with a function to handle updating the particle, and a texture to use for drawing it:

public class ParticleSystem<T> where T : struct, IParticle {
    public delegate bool Updater (ref T particle, int index);
SmokeParticles = new ParticleSystem<BasicParticle>(SmokeTexture, UpdateSmoke);
SparkParticles = new ParticleSystem<SparkParticle>(SparkTexture, UpdateSpark);

The IParticle interface contains all the properties the particle system needs to draw a particle. So, at runtime, to update and draw each particle system, I just call the appropriate methods:

SmokeParticles.Update();

SpriteBatch.Begin(SpriteBlendMode.AlphaBlend);
SmokeParticles.Draw(SpriteBatch, ViewportPosition);
SpriteBatch.End();

The updater function is responsible for updating every particle each frame, and also determines when it’s time for a particle to die and be removed.

    protected bool UpdateSmoke (ref BasicParticle particle, int index) {
        particle.Scale += 0.05f;
        particle.Rotation += 0.025f;
        particle.Opacity -= 0.01f;

        return (particle.Opacity <= 0.0f);
    }

In my case, I made a couple assumptions that allow me to simplify things some:

  • Particles don’t ever interact with each other.
  • Particles are not modified from outside the particle system after being created.

As a result, I was able to make this optimization (among others):

To remove a ‘dead’ particle, instead of having to use a potentially expensive method call like List.Remove or having to use a garbage-heavy data structure like a linked list, I can instead swap dead particles with the last live particle. Doing this moves the live particle forward in the list so that it will still get updated, and means that the last item in the list is now a dead particle – so all I have to do is reduce the particle count by one.

To integrate the particle system with the game, I wrote helper functions for ‘spawning’ particle effects at a given location, like this:

    public void SpawnSparks (Vector2 position) {
        var rng = new Random();
        Vector2 dir;

        for (int i = 0; i < 24; i++) {
            dir.X = rng.NextFloat(-1, 1);
            dir.Y = rng.NextFloat(-1, 1);
            dir.Normalize();

            SparkParticles.Spawn(new SparkParticle {
                Position = position,
                Opacity = rng.NextFloat(0.40f, 0.60f),
                Velocity = dir * rng.NextFloat(1.66f, 2.66f),
                Color = new Color(rng.NextFloat(0.8f, 1.0f), rng.NextFloat(0.45f, 0.65f), rng.NextFloat(0.2f, 0.35f), 1.0f),
                Scale = 0.35f
            });
        }
    }

This function does all the work of spawning a bunch of particles at the right location with randomized parameters, and the updater function does the work after that. The final bit of code goes in the grappling hook class:

    this.Stopped = true;
    _Game.SpawnSparks(this.Position);

The call to SpawnSparks spawns some spark particles at the location of the grappling hook when it first makes contact with a surface and stops.

After I got it working, I used it to add a few simple particle effects to go with some of the game mechanics already in the prototype. It definitely looks a bit nicer, and helps add a little more feedback for the player when doing things like performing a wall-jump.