#region File Description
//-----------------------------------------------------------------------------
// ParticleEmitter.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using Microsoft.Xna.Framework;
#endregion
namespace Particle3DSample
{
///
/// Helper for objects that want to leave particles behind them as they
/// move around the world. This emitter implementation solves two related
/// problems:
///
/// If an object wants to create particles very slowly, less than once per
/// frame, it can be a pain to keep track of which updates ought to create
/// a new particle versus which should not.
///
/// If an object is moving quickly and is creating many particles per frame,
/// it will look ugly if these particles are all bunched up together. Much
/// better if they can be spread out along a line between where the object
/// is now and where it was on the previous frame. This is particularly
/// important for leaving trails behind fast moving objects such as rockets.
///
/// This emitter class keeps track of a moving object, remembering its
/// previous position so it can calculate the velocity of the object. It
/// works out the perfect locations for creating particles at any frequency
/// you specify, regardless of whether this is faster or slower than the
/// game update rate.
///
public class ParticleEmitter
{
#region Fields
ParticleSystem particleSystem;
float timeBetweenParticles;
Vector3 previousPosition;
float timeLeftOver;
#endregion
///
/// Constructs a new particle emitter object.
///
public ParticleEmitter (ParticleSystem particleSystem,
float particlesPerSecond,Vector3 initialPosition)
{
this.particleSystem = particleSystem;
timeBetweenParticles = 1.0f / particlesPerSecond;
previousPosition = initialPosition;
}
///
/// Updates the emitter, creating the appropriate number of particles
/// in the appropriate positions.
///
public void Update (GameTime gameTime, Vector3 newPosition)
{
if (gameTime == null)
throw new ArgumentNullException ("gameTime");
// Work out how much time has passed since the previous update.
float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
if (elapsedTime > 0) {
// Work out how fast we are moving.
Vector3 velocity = (newPosition - previousPosition) / elapsedTime;
// If we had any time left over that we didn't use during the
// previous update, add that to the current elapsed time.
float timeToSpend = timeLeftOver + elapsedTime;
// Counter for looping over the time interval.
float currentTime = -timeLeftOver;
// Create particles as long as we have a big enough time interval.
while (timeToSpend > timeBetweenParticles) {
currentTime += timeBetweenParticles;
timeToSpend -= timeBetweenParticles;
// Work out the optimal position for this particle. This will produce
// evenly spaced particles regardless of the object speed, particle
// creation frequency, or game update rate.
float mu = currentTime / elapsedTime;
Vector3 position = Vector3.Lerp (previousPosition, newPosition, mu);
// Create the particle.
particleSystem.AddParticle (position, velocity);
}
// Store any time we didn't use, so it can be part of the next update.
timeLeftOver = timeToSpend;
}
previousPosition = newPosition;
}
}
}