Monogame: Particle systems

Understanding particle systems
In its simplest form, a particle system is a collection of primitives. The primitives within a particle system are known as particles. All the particles in a particle system have a common set of properties, such as life span, size, rate of change in size, and speed. By manipulating these properties in different ways, you can achieve various effects. In general, each particle executes a behavior based on its properties until its life span is over.
Another important aspect for a particle system is randomness. To create an effect such as an explosion, game developers often use random values to initialize a particle’s properties. Without a random factor, patterns often become apparent as the particle system executes. Overall, you can think of a particle system as a group or collection of particles. By randomizing each particle’s properties, you can achieve engaging effects for a variety of purposes.
With the basic understanding of the components of a particle system, you are ready to begin adding support for the upcoming particle classes. The first modification you need to make is adding color-tinting support within the TexturedPrimitive class. Adding this allows you to tint your images.

Modifying the TexturedPrimitive class
In your class for Textured Primitive, add the mTintColor variable and initialize it within the InitPrimitive() function:
protected Color mTintColor;

protected void InitPrimitive(String imageName, Vector2 position, Vector2 size, String label = null)
{

mTintColor = Color.White;


}
In the Draw() function, locate the SpriteBatch.Draw call and modify it to include the tint color:
Game1.sSpriteBatch.Draw(mImage,
destRect, // Area to be drawn in pixel space
null, //
mTintColor, //
mRotateAngle, // Angle to rotate (clockwise)
org, // Image reference position
SpriteEffects.None, 0f);

Creating the ParticlePrimitive class
Create a new folder named ParticleSupport. Then create a new class called ParticlePrimitive that inherits from the GameObject class, and save it in the new ParticleSupport folder you just created. Add the instance variables shown following to the ParticlePrimitive class to support life span, size change, and randomness:

public class ParticlePrimitive : GameObject
{
private float kLifeSpanRandomness = 0.4f;
private float kSizeChangeRandomness = 0.5f;
private float kSizeRandomness = 0.3f;
private float kSpeedRandomness = 0.1f;

// Number of updates before a particle disappear
private int mLifeSpan;
// How fast does the particle changes size
private float mSizeChangeRate;


}

Next, create a constructor that accepts a position, size, and life span for the particle. For this example, pass the ParticleImage.png image name in the base constructor call. Lastly, set the particle properties to the default values shown in the following code:

public ParticlePrimitive(Vector2 position, float size, int lifeSpan) :
base(“ParticleImage”, position, new Vector2(size, size))
{
mLifeSpan =(int)(lifeSpan * Game1.RandomNumber(-kLifeSpanRandomness,
kLifeSpanRandomness));

mVelocityDir.X = Game1.RandomNumber(-0.5f, 0.5f);
mVelocityDir.Y = Game1.RandomNumber(-0.5f, 0.5f);
mVelocityDir.Normalize();
mSpeed = Game1.RandomNumber(kSpeedRandomness);

mSizeChangeRate = Game1.RandomNumber(kSizeChangeRandomness);

mSize.X *= Game1.RandomNumber(1f-kSizeRandomness, 1+kSizeRandomness);
mSize.Y = mSize.X;
}

You need to override the existing update function within the base class. In the update function, first call the base class’s update, and then decrement the life span, adjust the particle’s size, and modify its tint color:

public override void Update()
{
base.Update();
mLifeSpan–; // Continue to approach expiration

// Change its size
mSize.X += mSizeChangeRate;
mSize.Y += mSizeChangeRate;

// Change the tintcolor randomly
Byte[] b = new Byte[3];
Game1.sRan.NextBytes(b);
mTintColor.R += b[0];
mTintColor.G += b[1];
mTintColor.B += b[2];
}

Finally, create an accessor called Expired to return the particle’s current life status. Returning false indicates that the particle life span is over.
public bool Expired { get { return (mLifeSpan < 0); } } Now that you have created the class for a particle, you can create the particle system itself. Creating the ParticleSystem class
Create a new class called ParticleSystem within the ParticleSupport folder. Add a collection of particles to the particle system using a list data structure. Don’t forget to initialize the list of particles within the constructor.

public class ParticleSystem
{
// Collection of particles
private List mAllParticles;

public ParticleSystem()
{
mAllParticles = new List();
}


}

Now add a function that creates a particle at a specific position. You can do this easily by passing in the desired position of the particle, creating a particle, and adding it to the collection.

public void AddParticleAt(Vector2 pos)
{
ParticlePrimitive particle = new ParticlePrimitive(pos, 2f, 50);
mAllParticles.Add(particle);
}

Next, create a function to update each particle within the collection. This function should iterate through each particle in the list, calling its update function. Additionally, check to see whether the particle has expired; if so, remove it from the list.

public void UpdateParticles()
{
int particleCounts = mAllParticles.Count;
for (int i = particleCounts- 1; i >= 0; i–)
{
mAllParticles[i].Update();
if (mAllParticles[i].Expired)
mAllParticles.RemoveAt(i); // Remove expired ones
}
}

Finally, create a function to draw the particle system. You do this by drawing each particle within the list. Additionally, you can apply a blend state of Additive and AlphaBlend to the particles. The details of both blend states are shown following.

public void DrawParticleSystem()
{
// 1. Switch blend mode to “Additive”
Game1.sSpriteBatch.End();
Game1.sSpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);

// 2. Draw all particles
foreach (var particle in mAllParticles)
particle.Draw();

// 3. Switch blend mode back to AlphaBlend
Game1.sSpriteBatch.End();
Game1.sSpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);

Understanding alpha and additive blending
Blending is a process of mixing overlapping colors to produce a new color. The blending process consists of three key components. First is the source color, which is the overlaying or top color. Second is the destination color, which is the bottom color—the color underneath the source color. The last color is the blended color, which is a color calculated from the source color and the destination color. Alpha blending and additive blending are two different ways of calculating a blended color.
Typically, alpha blending is achieved with the following equation:

getfile1

By inspecting this equation, you can see that when the source’s alpha is equal to 1, the Output _ Color equals the Source _ Color. Alternatively, when the source’s alpha is equal to 0, the Output _ Color equals the Destination _ Color. Logically this makes sense. If the source is completely opaque (has an alpha of 1), then the background color will not show through. However, if the source is completely transparent (has an alpha of 0), then the background color will show through unchanged. An alpha value between 0 and 1 will compute an output color that is a linear combination (blend) of the source and destination colors.
MonoGame achieves additive blending using the following equation:

getfile2

By inspecting this equation, you can see that the approach to additive blending is similar to alpha blending; however, there are some differences. The first difference is that Tint _ Color is included along with Source _ Alpha. Secondly, the destination color is added without the reference to Source _ Alpha. This means the bottom color is added to the top or overlaying color.
In addition to alpha and additive blending, there are other types, such as multiplicative blending. The type of blending you should use within your games depends upon the effect you’re trying to achieve. The figure below shows examples of the effects that alpha and additive blending produce.

getfile

You can now add the GameState class modifications necessary to use the particle system within your game.

Modifying the GameState class
Start by adding an instance variable for the particle system and initializing it within the constructor:

ParticleSystem mParticleSystem;

public GameState()
{

mParticleSystem = new ParticleSystem();
}

Next, call the particle system’s update within the game state’s update function. Additionally, create particles at the point of collision when a collision is detected. Do this by calling the AddParticleAt() function when a collision occurs. Remember that the collision detection logic has been separated into its own CollisionUpdate() function.

public void UpdateGame()
{

mParticleSystem.UpdateParticles();
}

private void CollisionUpdate()
{

#region Collide the hero with the flower

if (mHeroPixelCollision)
{
mParticleSystem.AddParticleAt(pixelCollisionPosition);
}

#endregion

#region Collide the hero with planes

if (mHeroPixelCollision)
{
mParticleSystem.AddParticleAt(pixelCollisionPosition);
}

#endregion
}

Lastly, simply draw the particle system by calling its function within the game state’s draw function:

public void DrawGame()
{
mFlower.Draw();
foreach (var p in mPlane)
p.Draw();
mHero.Draw();

mParticleSystem.DrawParticleSystem();


}

References:
Learn 2D Game Development with C#
By: Jebediah Pavleas; Jack Keng-Wei Chang; Kelvin Sung; Robert Zhu

5 thoughts on “Monogame: Particle systems

  1. Good day very cool blog!! Guy .. Beautiful .. Wonderful ..

    I’ll bookmark your site and take the feeds also? I’m happy to seek out
    a lot of helpful information right here in the post, we want work out extra strategies on this
    regard, thank you for sharing. . . . . .

    My website Hack day Hack

  2. My spouse and I stumbled over here by a different web address and thought I
    may as well check things out. I like what I see so now i’m following you.
    Look forward to looking over your web page again.

  3. I tend not to leave many responses, however i did
    soke searching and wound up here Luigi Cardarella | Monogame: Particle
    systems. And I do have a couple of questions for you if it’s
    allright. Is it only me or does it guve the impression like some oof these comments look ass
    if they are coming from brain dead folks? 😛 And, if you are posting at
    additional online sites, I would like to follow anything new you have
    to post. Could you list of all of your community sites
    like your Facebook page, twitter feed, or
    linkedin profile?

    Visit myy site – rihanna plastic surgery (Dewitt)

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

*