using Microsoft.Xna.Framework; using System; using System.Xml.Linq; namespace Barotrauma.Particles { class ParticleEmitter { private float emitTimer; private float burstEmitTimer; public readonly ParticleEmitterPrefab Prefab; public ParticleEmitter(XElement element) { Prefab = new ParticleEmitterPrefab(element); } public ParticleEmitter(ParticleEmitterPrefab prefab) { System.Diagnostics.Debug.Assert(prefab != null, "The prefab of a particle emitter cannot be null"); Prefab = prefab; } public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f) { emitTimer += deltaTime * amountMultiplier; burstEmitTimer += deltaTime; if (Prefab.ParticlesPerSecond > 0) { float emitInterval = 1.0f / Prefab.ParticlesPerSecond; while (emitTimer > emitInterval) { Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier); emitTimer -= emitInterval; } } if (burstEmitTimer < Prefab.EmitInterval) return; burstEmitTimer = 0.0f; for (int i = 0; i < Prefab.ParticleAmount * amountMultiplier; i++) { Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier); } } private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier) { angle += Rand.Range(Prefab.AngleMin, Prefab.AngleMax); Vector2 velocity = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * Rand.Range(Prefab.VelocityMin, Prefab.VelocityMax) * velocityMultiplier; var particle = GameMain.ParticleManager.CreateParticle(Prefab.ParticlePrefab, position, velocity, particleRotation, hullGuess); if (particle != null) { particle.Size *= Rand.Range(Prefab.ScaleMin, Prefab.ScaleMax); } } public Rectangle CalculateParticleBounds(Vector2 startPosition) { Rectangle bounds = new Rectangle((int)startPosition.X, (int)startPosition.Y, (int)startPosition.X, (int)startPosition.Y); for (float angle = Prefab.AngleMin; angle <= Prefab.AngleMax; angle += 0.1f) { Vector2 velocity = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * Prefab.VelocityMax; Vector2 endPosition = Prefab.ParticlePrefab.CalculateEndPosition(startPosition, velocity); bounds = new Rectangle( (int)Math.Min(bounds.X, endPosition.X), (int)Math.Min(bounds.Y, endPosition.Y), (int)Math.Max(bounds.X, endPosition.X), (int)Math.Max(bounds.Y, endPosition.Y)); } bounds = new Rectangle(bounds.X, bounds.Y, bounds.Width - bounds.X, bounds.Height - bounds.Y); return bounds; } } class ParticleEmitterPrefab { public readonly string Name; public readonly ParticlePrefab ParticlePrefab; public readonly float AngleMin, AngleMax; public readonly float VelocityMin, VelocityMax; public readonly float ScaleMin, ScaleMax; public readonly float EmitInterval; public readonly int ParticleAmount; public readonly float ParticlesPerSecond; public readonly bool CopyEntityAngle; public ParticleEmitterPrefab(XElement element) { Name = element.Name.ToString(); ParticlePrefab = GameMain.ParticleManager.FindPrefab(element.GetAttributeString("particle", "")); if (element.Attribute("startrotation") == null) { AngleMin = element.GetAttributeFloat("anglemin", 0.0f); AngleMax = element.GetAttributeFloat("anglemax", 0.0f); } else { AngleMin = element.GetAttributeFloat("angle", 0.0f); AngleMax = AngleMin; } AngleMin = MathHelper.ToRadians(MathHelper.Clamp(AngleMin, -360.0f, 360.0f)); AngleMax = MathHelper.ToRadians(MathHelper.Clamp(AngleMax, -360.0f, 360.0f)); if (element.Attribute("scalemin") == null) { ScaleMin = 1.0f; ScaleMax = 1.0f; } else { ScaleMin = element.GetAttributeFloat("scalemin", 1.0f); ScaleMax = Math.Max(ScaleMin, element.GetAttributeFloat("scalemax", 1.0f)); } if (element.Attribute("velocity") == null) { VelocityMin = element.GetAttributeFloat("velocitymin", 0.0f); VelocityMax = element.GetAttributeFloat("velocitymax", 0.0f); } else { VelocityMin = element.GetAttributeFloat("velocity", 0.0f); VelocityMax = VelocityMin; } EmitInterval = element.GetAttributeFloat("emitinterval", 0.0f); ParticlesPerSecond = element.GetAttributeInt("particlespersecond", 0); ParticleAmount = element.GetAttributeInt("particleamount", 0); CopyEntityAngle = element.GetAttributeBool("copyentityangle", false); } } }