//----------------------------------------------------------------------------- // ParticleSystem.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace AlienGameSample { /// /// A relatively simple particle system. We recycle particles instead of creating /// and destroying them as we need more. "Effects" are created via factory methods /// on ParticleSystem, rather than a data driven model due to the relatively low /// number of effects. /// public class ParticleSystem { Random random; Texture2D tank_tire; Texture2D tank_top; Texture2D fire; Texture2D smoke; SpriteBatch spriteBatch; List particles; public ParticleSystem(ContentManager content, SpriteBatch spriteBatch) { random = new Random(); particles = new List(); this.spriteBatch = spriteBatch; tank_tire = content.Load("tank_tire"); tank_top = content.Load("tank_top"); fire = content.Load("fire"); smoke = content.Load("smoke"); } /// /// Update all active particles. /// /// The amount of time elapsed since last Update. public void Update(float elapsed) { for (int i = 0; i < particles.Count; ++i) { particles[i].Life -= elapsed; if (particles[i].Life <= 0.0f) { continue; } particles[i].Position += particles[i].Velocity * elapsed; particles[i].Rotation += particles[i].RotationRate * elapsed; particles[i].Alpha += particles[i].AlphaRate * elapsed; particles[i].Scale += particles[i].ScaleRate * elapsed; if (particles[i].Alpha <= 0.0f) particles[i].Alpha = 0.0f; } } /// /// Draws the particles. /// public void Draw() { for (int i = 0; i < particles.Count; ++i) { Particle p = particles[i]; if (p.Life <= 0.0f) continue; float alphaF = 255.0f * p.Alpha; if (alphaF < 0.0f) alphaF = 0.0f; if (alphaF > 255.0f) alphaF = 255.0f; spriteBatch.Draw(p.Texture, p.Position, null, new Color(p.Color.R, p.Color.G, p.Color.B, (byte)alphaF), p.Rotation, new Vector2(p.Texture.Width / 2, p.Texture.Height / 2), p.Scale, SpriteEffects.None, 0.0f); } } /// /// Creats a particle, preferring to reuse a dead one in the particles list /// before creating a new one. /// /// Particle CreateParticle() { Particle p = null; for (int i = 0; i < particles.Count; ++i) { if (particles[i].Life <= 0.0f) { p = particles[i]; break; } } if (p == null) { p = new Particle(); particles.Add(p); } p.Color = Color.White; return p; } /// /// Creats the effect for when an alien dies. /// /// Where on the screen to create the effect. public void CreateAlienExplosion(Vector2 position) { Particle p = null; for (int i = 0; i < 8; ++i) { p = CreateParticle(); p.Position = position; p.RotationRate = -6.0f + 12.0f * (float)random.NextDouble(); p.Scale = 0.5f; p.ScaleRate = 0.25f;// *(float)random.NextDouble(); p.Alpha = 2.0f; p.AlphaRate = -1.0f; p.Velocity.X = -32.0f + 64.0f * (float)random.NextDouble(); p.Velocity.Y = -32.0f + 64.0f * (float)random.NextDouble(); p.Texture = smoke; p.Life = 2.0f; } for (int i = 0; i < 3; ++i) { p = CreateParticle(); p.Position = position; p.Position.X += -8.0f + 16.0f * (float)random.NextDouble(); p.Position.Y += -8.0f + 16.0f * (float)random.NextDouble(); p.RotationRate = -2.0f + 4.0f * (float)random.NextDouble(); p.Scale = 0.25f; p.ScaleRate = 1.0f;// *(float)random.NextDouble(); p.Alpha = 2.0f; p.AlphaRate = -1.0f; p.Velocity = Vector2.Zero; p.Texture = fire; p.Life = 2.0f; } } /// /// Creats the effect for when the player dies. /// /// Where on the screen to create the effect. public void CreatePlayerExplosion(Vector2 position) { Particle p = null; for (int i = 0; i < 16; ++i) { p = CreateParticle(); p.Position = position; p.RotationRate = -6.0f + 12.0f * (float)random.NextDouble(); p.Scale = 0.5f; p.ScaleRate = 0.25f;// *(float)random.NextDouble(); p.Alpha = 2.0f; p.AlphaRate = -1.0f; p.Velocity.X = -32.0f + 64.0f * (float)random.NextDouble(); p.Velocity.Y = -32.0f + -48.0f * (float)random.NextDouble(); p.Texture = smoke; p.Life = 2.0f; } p = CreateParticle(); p.Texture = tank_tire; p.Position = position; p.Scale = 1.0f; p.ScaleRate = 0.0f; p.Alpha = 2.0f; p.AlphaRate = -1.0f; p.Life = 2.0f; p.RotationRate = 0.5f; p.Rotation = 0.0f; p.Velocity = new Vector2(40.0f, -75.0f); p = CreateParticle(); p.Texture = tank_tire; p.Position = position; p.Scale = 1.0f; p.ScaleRate = 0.0f; p.Alpha = 2.0f; p.AlphaRate = -1.0f; p.Life = 2.0f; p.RotationRate = 0.5f; p.Rotation = 0.0f; p.Velocity = new Vector2(-45.0f, -90.0f); p = CreateParticle(); p.Texture = tank_top; p.Position = position; p.Scale = 1.0f; p.ScaleRate = 0.0f; p.Alpha = 2.0f; p.AlphaRate = -1.0f; p.Life = 2.0f; p.RotationRate = 2.5f; p.Rotation = 0.0f; p.Velocity = new Vector2(0.0f, -60.0f); for (int i = 0; i < 8; ++i) { p = CreateParticle(); p.Position = position; p.Position.X += -16.0f + 32.0f * (float)random.NextDouble(); p.Position.Y += -16.0f + 32.0f * (float)random.NextDouble(); p.RotationRate = -2.0f + 4.0f * (float)random.NextDouble(); p.Scale = 0.25f; p.ScaleRate = 1.0f;// *(float)random.NextDouble(); p.Alpha = 2.0f; p.AlphaRate = -1.0f; p.Velocity.X = -4.0f + 8.0f * (float)random.NextDouble(); p.Velocity.Y = -4.0f + -8.0f * (float)random.NextDouble(); p.Texture = fire; p.Life = 2.0f; } } /// /// Creats the mud/dust effect when the player moves. /// /// Where on the screen to create the effect. public void CreatePlayerDust(Player player) { for (int i = 0; i < 2; ++i) { Particle p = CreateParticle(); p.Texture = smoke; p.Color = new Color(125, 108, 43); p.Position.X = player.Position.X + player.Width * (float)random.NextDouble(); p.Position.Y = player.Position.Y + player.Height - 3.0f * (float)random.NextDouble(); p.Alpha = 1.0f; p.AlphaRate = -2.0f; p.Life = 0.5f; p.Rotation = 0.0f; p.RotationRate = -2.0f + 4.0f * (float)random.NextDouble(); p.Scale = 0.25f; p.ScaleRate = 0.5f; p.Velocity.X = -4 + 8.0f * (float)random.NextDouble(); p.Velocity.Y = -8 + 4.0f * (float)random.NextDouble(); } } /// /// Creats the effect for when the player fires a bullet. /// /// Where on the screen to create the effect. public void CreatePlayerFireSmoke(Player player) { for (int i = 0; i < 8; ++i) { Particle p = CreateParticle(); p.Texture = smoke; p.Color = Color.White; p.Position.X = player.Position.X + player.Width / 2; p.Position.Y = player.Position.Y; p.Alpha = 1.0f; p.AlphaRate = -1.0f; p.Life = 1.0f; p.Rotation = 0.0f; p.RotationRate = -2.0f + 4.0f * (float)random.NextDouble(); p.Scale = 0.25f; p.ScaleRate = 0.25f; p.Velocity.X = -4 + 8.0f * (float)random.NextDouble(); p.Velocity.Y = -16.0f + -32.0f * (float)random.NextDouble(); } } } /// /// A basic particle. Since this is strictly a data class, I decided to not go /// the full property route and used public fields instead. /// public class Particle { public Vector2 Position; public Vector2 Velocity; public Texture2D Texture; public float RotationRate; public float Rotation; public float Life; public float AlphaRate; public float Alpha; public float ScaleRate; public float Scale; public Color Color = Color.White; } }