Spring 2010 Week2

Start Files: circle.png star.png diamond.png

Finish Project: Week2Finish.zip

Fire Project: Week2Fire.zip

Notes:

Today we didn't have a start project but we did start with the three files above. Actually, there is a really good Particle Engine tutorial Particle Engine tutorial that is nearly identical to what I went over in class. Just follow that tutorial and you will have done everything I did in class. Or if you don't want to bother doing that, you can download the finish project above and get started right away!

The rest of these notes will go over something I did at the very end of class after many of you left. The current particle engine looks pretty cool, with a bunch of stars and diamonds shooting out of it like a magic wand or something. However, we want to have things like fire, sparks, and explosions.

Let's make some small, simple changes to the code to make it look more like fire.

First thing we will do is change the color from a completely random color to colors that are more fiery. In ParticleEngine.GenerateNewParticles() the color initialization looks like this:

Color color = new Color(
        (float)random.NextDouble(),
        (float)random.NextDouble(),
        (float)random.NextDouble());

Change it to this:
Color color = new Color(
    (float)random.NextDouble() * 0.4f + 0.6f,
    (float)random.NextDouble() * 0.4f,
    (float)random.NextDouble() * 0.1f);

Even though all the values are still random, we're weighting the values differently. Notice that there is almost no blue now (but still a little bit). There is also less green (maximum 0.4f) and more red (between 0.4f and 1.0f). Run the program and see how it looks. Not quite fire, but a little bit better.
This next change will actually make a huge difference. In ParticleEngine.Draw() change the first line of code from this:
spriteBatch.Begin();

to this;
spriteBatch.Begin(SpriteBlendMode.Additive);

Run the code and see if it looks any better. While it still doesn't look like flame at all, it's getting better! Normally when drawing with SpriteBatch we use SpriteBlendMode.AlphaBlend which just draws it normal and allows for transparency. With SpriteBlendMode.Additive, the Red, Green, and Blue values of each texture are added together instead of blended. Closer to the emitter location, there are more textures so more colors are being added together. That's why it's white in the center. As the textures move away they spread out and the colors become more distinct.
Real fire doesn't explode out like how our particle engine is doing right now - it goes up a little bit. Let's add Acceleration to the particles so they go up. Add this property to the Particle class:
public Vector2 Acceleration { get; set; }

Then, in the Particle constructor, add the following line:
Acceleration = new Vector2(0, -0.05f);

This sets the Y acceleration to -0.05f. Next thing to do is update the Velocity to reflect the new Accleration. This is done in Particle.Update(). Add this line right after TTL—; and before Position += Velocity;:
Velocity += Acceleration;

Run the program and take a look. It's starting to look like fire now! There are still a few things we can do to make it look even better, so let's keep going. An obvious thing we can do is change the textures from stars and diamonds to something that looks more like flame.
Add RealFlame.png to your Content folder (don't know how to load content?). To make the particles have the new texture, go to Game1.LoadContent() and replace these lines:
textures.Add(Content.Load<Texture2D>("circle"));
textures.Add(Content.Load<Texture2D>("diamond"));
textures.Add(Content.Load<Texture2D>("star"));

with this one:
textures.Add(Content.Load<Texture2D>("RealFlame"));

If you run it now, it will look really bad. RealFlame.png is much larger than the other textures we had, so we need to scale it down. In ParticleEngine.GenerateNewParticle() change the size initialization from this:
float size = (float)random.NextDouble();

to this:
float size = (float)random.NextDouble() / 4.0f;

We're just making the texture 4 times smaller on average. Now run the program and see the improvement.
There are still a few things that we can change to make it look better. One thing that I don't really like is that the textures spin a little too quickly. This is easy to change. Still in ParticleEngine.GenerateNewparticle(), change the angularVelocity initialization from this:
float angularVelocity = 0.1f * (float)(random.NextDouble() * 2 - 1);

to this:
float angularVelocity = 0.05f * (float)(random.NextDouble() * 2 - 1);

We change the max angularVelocity from 0.1f to 0.05f.
There's one last change we'll make. Notice how when a particle's TTL is 0 it just disappears? it doesn't look very good. Let's have the particles slowly fade out instead. To do this, we'll need another property in Particle.cs called TTTL (Total Time To Live). Add this line below the other properties in Particle.cs:
public float TTTL { get; set; }

Note that this value is a float and not an int like TTL. I'll explain why shortly. Because TTTL is the total TTL, we need to initialize it as such. In the constructor for Particle and the bottom, put this line of code:
TTTL = TTL;

Last thing we need to do to get the particle to fade out is to decrease Color's alpha value over the lifetime of the particle. At the bottom of Particle.Update(), put this line of code:
Color = new Color(Color, TTL / TTTL);

Now run the program. See how the individual particles no longer just vanish but actually fade out? That's what we wanted. Now why did TTTL need to be a float and not an int? If you'd like, switch it to and int and see what happens. No more particles! Remember that when you divide an int by an int it returns and int. TTL will always be a value between 0 and TTTL, and when divided by TTTL, will always return a value between 0 and 1. If both TTL and TTTL are ints, it will always return an alpha value of 0, which is completely transparent.
Finally, we'll make one last change - the fire looks a lot smaller than before because the colors fade out. Let's make the particles live just a little longer. In ParticleEngine.GenerateNewParticle(), change the ttl initialization from this:
int ttl = 20 + random.Next(40);

to this:
int ttl = 50 + random.Next(40);

All we're doing is adding half a second (or 30 updates) to each particle's lifetime. Now take a look. Obviously, it's still far from a perfectly realistic flame, but looks believable enough.

With just a few different tweaks, we could create smoke, water particles, sparks, explosions, gas, dust, or machine gun shells.

back to SIGXNA

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License