/* * ParticleEngine.cs * Authors: Brian Murphy * Copyright (c) 2007-2008 Cornell University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using tAC_Engine.Graphics.Cameras; using TACParticleEngine.Emitters; using Util; namespace TACParticleEngine.Particles { /// /// Handles creation, updating, and rendering of all emitters associtied with it /// public class ParticleEngine : DrawableGameScreenComponent, ICloneable { #region Fields // Whether to draw using GPU or CPU private bool mGPURendering; // Current sprite batch renderer private SpriteBatch mSpriteBatch; // Current active camera private Camera mActiveCamera; // Current viewport used for rendering to private Viewport mViewport; // Current content manager used in managing content private ContentManager mContent; // Boolean value to let the particle manager know when to dispose of this private bool mToDestroy; // List of emitters private readonly List mEmitterList; #endregion #region Properties /// /// Sets whether or not the engine will draw using GPU or CPU rendering /// public bool GPURendering { set { mGPURendering = value; } } /// /// Sets the SpriteBatch object to be used in CPU rendering /// public SpriteBatch SpriteBatch { set { mSpriteBatch = value; } } /// /// Sets the active camera that is used for rendering /// public Camera ActiveCamera { set { mActiveCamera = value; } } /// /// Sets the viewport to draw within for CPU rendering /// public Viewport Viewport { set { mViewport = value; } } /// /// Gets/Sets whether this should be destroyed /// public bool ToDestory { get { return mToDestroy; } set { mToDestroy = value; } } /// /// Sets the current content manager used for content management /// public ContentManager Content { set { mContent = value; } } /// /// Gets the list of emitters within the particle engine /// public List Emitters { get { return mEmitterList; } } /// /// True if any of the emitters in the engine are still active /// *Note* active means that it is still able to draw while alive /// public bool EmitterActive { get { foreach (Emitter emitter in mEmitterList) { if (emitter.IsActive) { return true; } } return false; } } /// /// True if any of the emitters are alive /// *Note* alive means that it's lifetime has not been exceeded /// public bool EmitterAlive { get { foreach (Emitter emitter in mEmitterList) { if (emitter.Alive) { return true; } } return false; } } /// /// True if all of the particles in all emitters are finished drawing /// *Note* that this is typically for when an emitter is no longer alive /// public bool EmitterParticlesDone { get { foreach (Emitter emitter in mEmitterList) { if (!emitter.ParticlesDone) { return false; } } return true; } } /// /// Used for clearing out unused particle engines /// public static readonly Predicate NotAlive = delegate(ParticleEngine engine) { return (engine.mToDestroy && !engine.EmitterActive); }; #endregion #region Creation /// /// Particle Engine constuctor which sets its list of emitters to the given list /// /// The list of emitters the particle engine will use public ParticleEngine(List emitterList) { mEmitterList = emitterList; mToDestroy = false; } /// /// Returns a copy of this particle engine /// /// A cloned copy of this particle engine public object Clone() { List emitters = new List(); foreach (Emitter emitter in Emitters) { emitters.Add((Emitter)emitter.Clone()); } return new ParticleEngine(emitters); } #endregion #region File I/O /// /// Reads in a xml particle file and stores it as a new particle effect /// /// The name of the particle file to read in /// A new particle engine created for the read in file public static ParticleEngine LoadFromFile(string filename) { System.Xml.XmlDocument xml = new System.Xml.XmlDocument(); xml.Load(filename); ParticleCompiled ret = new ParticleCompiled(); foreach (System.Xml.XmlNode node in xml.GetElementsByTagName("particle")[0].ChildNodes) { EmitterInfo emitter = new EmitterInfo(); foreach (System.Xml.XmlNode info in node.ChildNodes) { if (info.Name.Equals("type")) emitter.Type = info.InnerText; if (info.Name.Equals("textureName")) emitter.TextureName = info.InnerText; if (info.Name.Equals("blendEffect")) emitter.BlendEffect = (SpriteBlendMode)Enum.Parse(emitter.BlendEffect.GetType(), info.InnerText, true); if (info.Name.Equals("positions")) { List vertices = new List(); String[] dots = info.InnerText.TrimStart('(').TrimEnd(')').Replace(")(", " ").Split(' '); foreach (String point in dots) { String[] vertex = point.Split(','); vertices.Add(new Vector3(float.Parse(vertex[0]), float.Parse(vertex[1]), float.Parse(vertex[2]))); } emitter.Positions = vertices; } if (info.Name.Equals("sprayRange")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.SprayRange = new Vector3( float.Parse(component[0]), float.Parse(component[1]), float.Parse(component[2])); } if (info.Name.Equals("direction")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.Direction = new Vector3( float.Parse(component[0]), float.Parse(component[1]), float.Parse(component[2])); } if (info.Name.Equals("minVel")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MinVel = new Vector3( float.Parse(component[0]), float.Parse(component[1]), float.Parse(component[2])); } if (info.Name.Equals("maxVel")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MaxVel = new Vector3( float.Parse(component[0]), float.Parse(component[1]), float.Parse(component[2])); } if (info.Name.Equals("emitLifetime")) emitter.EmitLifetime = float.Parse(info.InnerText); if (info.Name.Equals("particlesPerSec")) emitter.ParticlePersSec = int.Parse(info.InnerText); if (info.Name.Equals("particleLifetime")) emitter.ParticleLifetime = float.Parse(info.InnerText); if (info.Name.Equals("particleAmount")) emitter.ParticleAmount = int.Parse(info.InnerText); if (info.Name.Equals("minStartSpeed")) emitter.MinStartSpeed = float.Parse(info.InnerText); if (info.Name.Equals("maxStartSpeed")) emitter.MaxStartSpeed = float.Parse(info.InnerText); if (info.Name.Equals("minEndSpeed")) emitter.MinEndSpeed = float.Parse(info.InnerText); if (info.Name.Equals("maxEndSpeed")) emitter.MaxEndSpeed = float.Parse(info.InnerText); if (info.Name.Equals("minStartColor")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MinStartColor = new Vector4( float.Parse(component[0]), float.Parse(component[1]), float.Parse(component[2]), float.Parse(component[3])); } if (info.Name.Equals("maxStartColor")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MaxStartColor = new Vector4( float.Parse(component[0]), float.Parse(component[1]), float.Parse(component[2]), float.Parse(component[3])); } if (info.Name.Equals("minEndColor")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MinEndColor = new Vector4( float.Parse(component[0]), float.Parse(component[1]), float.Parse(component[2]), float.Parse(component[3])); } if (info.Name.Equals("maxEndColor")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MaxEndColor = new Vector4( float.Parse(component[0]), float.Parse(component[1]), float.Parse(component[2]), float.Parse(component[3])); } if (info.Name.Equals("minStartSize")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MinStartSize = new Vector2( float.Parse(component[0]), float.Parse(component[1])); } if (info.Name.Equals("maxStartSize")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MaxStartSize = new Vector2( float.Parse(component[0]), float.Parse(component[1])); } if (info.Name.Equals("minEndSize")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MinEndSize = new Vector2( float.Parse(component[0]), float.Parse(component[1])); } if (info.Name.Equals("maxEndSize")) { String[] component = info.InnerText.TrimStart('(').TrimEnd(')').Split(','); emitter.MaxEndSize = new Vector2( float.Parse(component[0]), float.Parse(component[1])); } if (info.Name.Equals("scale")) { emitter.Scale = float.Parse(info.InnerText); } if (info.Name.Equals("scaleSpeed")) { emitter.ScaleSpeed = float.Parse(info.InnerText); } } ret.EmitterInfoList.Add(emitter); } List emitterInfoList = ret.EmitterInfoList; List emitters = new List(); foreach (EmitterInfo info in emitterInfoList) { if (info.Type.Equals("SplineEmitter")) { emitters.Add(new SplineEmitter(info.Positions.ToArray(), info.Scale, info.ScaleSpeed, info.BlendEffect, info.TextureName, info.ParticlePersSec, info.ParticleAmount, info.EmitLifetime, info.ParticleLifetime, info.MinStartSize, info.MaxStartSize, info.MinEndSize, info.MaxEndSize, info.MinStartSpeed, info.MaxStartSpeed, info.MinEndSpeed, info.MaxEndSpeed, info.MinStartColor, info.MaxStartColor, info.MinEndColor, info.MaxEndColor)); } else if (info.Type.Equals("PointEmitter")) { emitters.Add(new PointEmitter(info.Positions[0], info.BlendEffect, info.TextureName, info.ParticlePersSec, info.ParticleAmount, info.EmitLifetime, info.ParticleLifetime, info.MinStartSize, info.MaxStartSize, info.MinEndSize, info.MaxEndSize, info.MinStartSpeed, info.MaxStartSpeed, info.MinEndSpeed, info.MaxEndSpeed, info.MinStartColor, info.MaxStartColor, info.MinEndColor, info.MaxEndColor)); } else if (info.Type.Equals("SprayEmitter")) { emitters.Add(new SprayEmitter(info.Positions[0], info.SprayRange, info.Direction, info.BlendEffect, info.TextureName, info.ParticlePersSec, info.ParticleAmount, info.EmitLifetime, info.ParticleLifetime, info.MinStartSize, info.MaxStartSize, info.MinEndSize, info.MaxEndSize, info.MinStartSpeed, info.MaxStartSpeed, info.MinEndSpeed, info.MaxEndSpeed, info.MinStartColor, info.MaxStartColor, info.MinEndColor, info.MaxEndColor)); } else if (info.Type.Equals("DirectionalEmitter")) { emitters.Add(new DirectionalEmitter(info.Positions[0], info.MinVel, info.MaxVel, info.BlendEffect, info.TextureName, info.ParticlePersSec, info.ParticleAmount, info.EmitLifetime, info.ParticleLifetime, info.MinStartSize, info.MaxStartSize, info.MinEndSize, info.MaxEndSize, info.MinStartSpeed, info.MaxStartSpeed, info.MinEndSpeed, info.MaxEndSpeed, info.MinStartColor, info.MaxStartColor, info.MinEndColor, info.MaxEndColor)); } } return new ParticleEngine(emitters); } /// /// Saves all the information of the particle effect into an xml file of the given name /// /// The name of the xml file to save to public void SaveToFile(string filename) { System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(filename, null); writer.WriteStartDocument(); writer.WriteComment(filename.Substring(filename.LastIndexOf("\\") + 1) + "\nCopyright (c) 2008 Cornell University\n\n" + "This program is free software; you can redistribute it and/or\n" + "modify it under the terms of the GNU General Public License\n" + "as published by the Free Software Foundation; either version 2\n" + "of the License, or (at your option) any later version.\n\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA."); writer.WriteWhitespace("\n\n"); writer.WriteStartElement("particle"); writer.WriteWhitespace("\n"); foreach (Emitter emitter in mEmitterList) { writer.WriteStartElement("emitter"); writer.WriteWhitespace("\n"); if (emitter is DirectionalEmitter) { writer.WriteStartElement("type"); writer.WriteString("DirectionalEmitter"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("positions"); writer.WriteString("(" + emitter.EmitterPosition.X + "," + emitter.EmitterPosition.Y + "," + emitter.EmitterPosition.Z + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("minVel"); writer.WriteString("(" + ((DirectionalEmitter)emitter).MinVel.X + "," + ((DirectionalEmitter)emitter).MinVel.Y + "," + ((DirectionalEmitter)emitter).MinVel.Z + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("maxVel"); writer.WriteString("(" + ((DirectionalEmitter)emitter).MaxVel.X + "," + ((DirectionalEmitter)emitter).MaxVel.Y + "," + ((DirectionalEmitter)emitter).MaxVel.Z + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); } if (emitter is PointEmitter) { writer.WriteStartElement("type"); writer.WriteString("PointEmitter"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("positions"); writer.WriteString("(" + emitter.EmitterPosition.X + "," + emitter.EmitterPosition.Y + "," + emitter.EmitterPosition.Z + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); } if (emitter is SplineEmitter) { writer.WriteStartElement("type"); writer.WriteString("SplineEmitter"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("positions"); string tempStr = ""; Vector3[] tempArr = ((SplineEmitter)emitter).EmitterPositions; for (int i = tempArr.Length - 1; i >= 0; --i) { tempStr += "(" + tempArr[i].X + "," + tempArr[i].Y + "," + tempArr[i].Z + ")"; } writer.WriteString(tempStr); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("direction"); writer.WriteString("(" + emitter.Direction.X + "," + emitter.Direction.Y + "," + emitter.Direction.Z + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("scale"); writer.WriteString(((SplineEmitter)emitter).Scale.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("scaleSpeed"); writer.WriteString(((SplineEmitter)emitter).ScaleSpeed.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); } if (emitter is SprayEmitter) { writer.WriteStartElement("type"); writer.WriteString("SprayEmitter"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("positions"); writer.WriteString("(" + emitter.EmitterPosition.X + "," + emitter.EmitterPosition.Y + "," + emitter.EmitterPosition.Z + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("direction"); writer.WriteString("(" + emitter.Direction.X + "," + emitter.Direction.Y + "," + emitter.Direction.Z + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("sprayRange"); writer.WriteString("(" + ((SprayEmitter)emitter).SprayRange.X + "," + ((SprayEmitter)emitter).SprayRange.Y + "," + ((SprayEmitter)emitter).SprayRange.Z + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); } writer.WriteStartElement("textureName"); writer.WriteString(emitter.TextureName); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("blendEffect"); writer.WriteString(emitter.BlendEffect.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("emitLifetime"); writer.WriteString(emitter.EmitLifetime.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("particlesPerSec"); writer.WriteString(emitter.ParticlesPerSec.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("particleAmount"); writer.WriteString(emitter.PaticleAmount.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("particleLifetime"); writer.WriteString(emitter.ParticleLifetime.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n\n"); writer.WriteStartElement("minStartSpeed"); writer.WriteString(emitter.MinStartSpeed.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("maxStartSpeed"); writer.WriteString(emitter.MaxStartSpeed.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("minEndSpeed"); writer.WriteString(emitter.MinEndSpeed.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("maxStartSpeed"); writer.WriteString(emitter.MaxEndSpeed.ToString()); writer.WriteEndElement(); writer.WriteWhitespace("\n\n"); writer.WriteComment(" (r,g,b,a) range 0.0-1.0 "); writer.WriteWhitespace("\n"); writer.WriteStartElement("minStartColor"); writer.WriteString("(" + emitter.MinStartColor.X + "," + emitter.MinStartColor.Y + "," + emitter.MinStartColor.Z + "," + emitter.MinStartColor.W + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("maxStartColor"); writer.WriteString("(" + emitter.MaxStartColor.X + "," + emitter.MaxStartColor.Y + "," + emitter.MaxStartColor.Z + "," + emitter.MaxStartColor.W + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("minEndColor"); writer.WriteString("(" + emitter.MinEndColor.X + "," + emitter.MinEndColor.Y + "," + emitter.MinEndColor.Z + "," + emitter.MinEndColor.W + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("maxEndColor"); writer.WriteString("(" + emitter.MaxEndColor.X + "," + emitter.MaxEndColor.Y + "," + emitter.MaxEndColor.Z + "," + emitter.MaxEndColor.W + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n\n"); writer.WriteComment(" (x,y) "); writer.WriteWhitespace("\n"); writer.WriteStartElement("minstartSize"); writer.WriteString("(" + emitter.MinStartSize.X + "," + emitter.MinStartSize.Y + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("maxStartSize"); writer.WriteString("(" + emitter.MaxStartSize.X + "," + emitter.MaxStartSize.Y + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("minEndSize"); writer.WriteString("(" + emitter.MinEndSize.X + "," + emitter.MinEndSize.Y + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteStartElement("maxEndSize"); writer.WriteString("(" + emitter.MaxEndSize.X + "," + emitter.MaxEndSize.Y + ")"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); writer.WriteEndElement(); writer.WriteWhitespace("\n"); } writer.WriteEndElement(); writer.WriteEndDocument(); writer.Close(); } #endregion #region Management /// /// Reloads in content that we are using whenever the graphics device loses focus so as to not crash program /// public void Load() { for (int i = mEmitterList.Count - 1; i >= 0; i--) { mEmitterList[i].Content = mContent; mEmitterList[i].LoadContent(); } } /// /// Unloads content so as to not take up too much memory. Primarily used for minigames. /// public void Unload() { for (int i = mEmitterList.Count - 1; i >= 0; i--) { mEmitterList[i].UnloadContent(); } } /// /// Disposes necessary objects. /// /// Whether or not this is currently being disposed of protected override void Dispose(bool disposing) { if (disposing) { if (mEmitterList.Count > 0) { for (int i = mEmitterList.Count - 1; i >= 0; --i) { mEmitterList[i].Dispose(); mEmitterList[i] = null; } mEmitterList.Clear(); } } base.Dispose(disposing); } #endregion #region Render /// /// Handles all rendering of particles using GPU or CPU rendering /// /// The total game time public override void Draw(GameTime gameTime) { if (EmitterActive) { if (mGPURendering) { // Set point sprite values Game.GraphicsDevice.RenderState.PointSpriteEnable = true; Game.GraphicsDevice.RenderState.PointSizeMax = 256; // Set the alpha blend mode Game.GraphicsDevice.RenderState.AlphaBlendEnable = true; Game.GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add; Game.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha; // Set the alpha test mode Game.GraphicsDevice.RenderState.AlphaTestEnable = true; Game.GraphicsDevice.RenderState.AlphaFunction = CompareFunction.Greater; Game.GraphicsDevice.RenderState.ReferenceAlpha = 0; // Enable the depth buffer (so particles will not be visible through // solid objects like the ground plane), but disable depth writes // (so particles will not obscure other particles). Game.GraphicsDevice.RenderState.DepthBufferEnable = true; Game.GraphicsDevice.RenderState.DepthBufferWriteEnable = false; // Do the actually rendering for (int i = mEmitterList.Count - 1; i >= 0; --i) { mEmitterList[i].RenderGPU(mActiveCamera); } // Reset a couple of the more unusual renderstates that we changed, // so as not to mess up any other subsequent drawing. Game.GraphicsDevice.RenderState.PointSpriteEnable = false; Game.GraphicsDevice.RenderState.DepthBufferWriteEnable = true; } else { for (int i = mEmitterList.Count - 1; i >= 0; --i) { mEmitterList[i].RenderCPU(mSpriteBatch, mActiveCamera, mViewport); } } } } #endregion #region Update /// /// Updates all emitters inside of engine /// /// The time since last call cycle public void Update(float elapsedTime) { for (int i = mEmitterList.Count - 1; i >= 0; i--) { mEmitterList[i].Update(elapsedTime); } } #endregion #region Modifiers /// /// Sets the scale size for a spline emitter /// *Note* has no effect on a non-spline emitter /// /// The size the emitter will scale by public void SetSplineScale(float scale) { foreach (Emitter emitter in mEmitterList) { if (emitter is SplineEmitter) { ((SplineEmitter)emitter).Scale = scale; } } } /// /// Sets the specified particle engine to either active or inactive /// /// True to activate the particle engine, false to deactivate it public void SetActive(bool isActive) { foreach (Emitter emitter in mEmitterList) { emitter.IsActive = isActive; } } /// /// Sets the positions of all the points of all spline emitters within the particle engine /// /// The new positions to put the spline points at public void SetEnginePositions(Vector3[] Positions) { foreach (Emitter emitter in mEmitterList) { if (emitter is SplineEmitter) { (emitter as SplineEmitter).EmitterPositions = Positions; } } } /// /// Sets the position of all the emitters within the particle engine /// /// The new position to put the particle at public void SetEnginePosition(Vector3 Position) { foreach (Emitter emitter in mEmitterList) { emitter.EmitterPosition = Position; } } /// /// Sets the color of all the emitters within the particle engine /// /// The new color to set the particle to /// Whether the new speed remains constant or decays public void SetEngineColor(Vector4 Color, bool Constant) { if (Constant) { foreach (Emitter emitter in mEmitterList) { emitter.StartColor = Color; emitter.EndColor = Color; } } else { foreach (Emitter emitter in mEmitterList) { emitter.StartColor = Color; } } } /// /// Sets the size of all the emitters within the particle engine /// /// The new size to set the particle to public void SetEngineSize(Vector2 Size) { foreach (Emitter emitter in mEmitterList) { emitter.Size = Size; } } /// /// Sets the speed of all emitters within the particle engine /// /// The new speed to set the particle to /// Whether the new speed remains constant or decays public void SetEngineSpeed(float Speed, bool Constant) { if (Constant) { foreach (Emitter emitter in mEmitterList) { emitter.StartSpeed = Speed; emitter.EndSpeed = Speed; } } else { foreach (Emitter emitter in mEmitterList) { emitter.StartSpeed = Speed; } } } /// /// Sets the direction of all emitters within the particle engine /// /// The new direction to set the particle to public void SetEngineDirection(Vector3 Direction) { foreach (Emitter emitter in mEmitterList) { emitter.Direction = Direction; } } /// /// Sets the lifetime of all particles in all emitters within the particle engine /// /// The new lifetime to set the particle to public void SetEngineParticleLifetime(float Lifetime) { foreach (Emitter emitter in mEmitterList) { emitter.ParticleLifetime = Lifetime; } } /// /// Sets the amount of particles to be active at one time. /// /// The amount of particles public void SetEngineParticles(float Num) { foreach (Emitter emitter in mEmitterList) { emitter.ParticlesPerSec = Num / emitter.ParticleLifetime; } } /// /// Sets the amount of particles created per second /// /// The amount of particles created per second public void SetEngineParticlesPerSec(float NumPerSec) { foreach (Emitter emitter in mEmitterList) { emitter.ParticlesPerSec = NumPerSec; } } /// /// Sets whether or not particles directions will be random /// /// Whether or not particles will move in a random direction public void SetRandomDirection(bool Random) { foreach (Emitter emitter in mEmitterList) { emitter.RandomDirection = Random; } } #endregion } }