diff --git a/Barotrauma/BarotraumaClient/Source/GameMain.cs b/Barotrauma/BarotraumaClient/Source/GameMain.cs index 2e6deadeb..829a06b66 100644 --- a/Barotrauma/BarotraumaClient/Source/GameMain.cs +++ b/Barotrauma/BarotraumaClient/Source/GameMain.cs @@ -293,6 +293,7 @@ namespace Barotrauma yield return CoroutineStatus.Running; ParticleManager = new ParticleManager("Content/Particles/ParticlePrefabs.xml", GameScreen.Cam); + ParticleManager.LoadPrefabs(); DecalManager = new DecalManager("Content/Particles/DecalPrefabs.xml"); yield return CoroutineStatus.Running; diff --git a/Barotrauma/BarotraumaClient/Source/Particles/Particle.cs b/Barotrauma/BarotraumaClient/Source/Particles/Particle.cs index 8272abf7c..8bec28056 100644 --- a/Barotrauma/BarotraumaClient/Source/Particles/Particle.cs +++ b/Barotrauma/BarotraumaClient/Source/Particles/Particle.cs @@ -38,6 +38,7 @@ namespace Barotrauma.Particles private float lifeTime; private Vector2 velocityChange; + private Vector2 velocityChangeWater; private Vector2 drawPosition; private float drawRotation; @@ -46,6 +47,8 @@ namespace Barotrauma.Particles private List hullGaps; + private List subEmitters = new List(); + private float animState; private int animFrame; @@ -71,6 +74,12 @@ namespace Barotrauma.Particles set { velocityChange = value; } } + public Vector2 VelocityChangeWater + { + get { return velocityChangeWater; } + set { velocityChangeWater = value; } + } + public Vector2 Velocity { get { return velocity; } @@ -90,6 +99,8 @@ namespace Barotrauma.Particles animState = 0; animFrame = 0; + dragWait = 0; + dragVec = Vector2.Zero; currentHull = Hull.FindHull(position, hullGuess); @@ -121,9 +132,16 @@ namespace Barotrauma.Particles alpha = prefab.StartAlpha; velocityChange = prefab.VelocityChangeDisplay; + velocityChangeWater = prefab.VelocityChangeWaterDisplay; OnChangeHull = null; + subEmitters.Clear(); + foreach (ParticleEmitterPrefab emitterPrefab in prefab.SubEmitters) + { + subEmitters.Add(new ParticleEmitter(emitterPrefab)); + } + if (prefab.DeleteOnCollision || prefab.CollidesWithWalls) { hullGaps = currentHull == null ? new List() : currentHull.ConnectedGaps; @@ -158,19 +176,26 @@ namespace Barotrauma.Particles rotation += angularVelocity * deltaTime; } - if (prefab.WaterDrag > 0.0f && - (currentHull == null || (currentHull.Submarine != null && position.Y - currentHull.Submarine.DrawPosition.Y < currentHull.Surface))) + bool inWater = (currentHull == null || (currentHull.Submarine != null && position.Y - currentHull.Submarine.DrawPosition.Y < currentHull.Surface)); + if (inWater) { - ApplyDrag(prefab.WaterDrag, deltaTime); + velocity.X += velocityChangeWater.X * deltaTime; + velocity.Y += velocityChangeWater.Y * deltaTime; + if (prefab.WaterDrag > 0.0f) + { + ApplyDrag(prefab.WaterDrag, deltaTime); + } } - else if (prefab.Drag > 0.0f) + else { - ApplyDrag(prefab.Drag, deltaTime); + velocity.X += velocityChange.X * deltaTime; + velocity.Y += velocityChange.Y * deltaTime; + if (prefab.Drag > 0.0f) + { + ApplyDrag(prefab.Drag, deltaTime); + } } - velocity.X += velocityChange.X * deltaTime; - velocity.Y += velocityChange.Y * deltaTime; - size.X += sizeChange.X * deltaTime; size.Y += sizeChange.Y * deltaTime; @@ -191,6 +216,11 @@ namespace Barotrauma.Particles lifeTime -= deltaTime; if (lifeTime <= 0.0f || alpha <= 0.0f || size.X <= 0.0f || size.Y <= 0.0f) return false; + foreach (ParticleEmitter emitter in subEmitters) + { + emitter.Emit(deltaTime, position, currentHull); + } + if (!prefab.DeleteOnCollision && !prefab.CollidesWithWalls) return true; if (currentHull == null) @@ -200,8 +230,7 @@ namespace Barotrauma.Particles { if (prefab.DeleteOnCollision) return false; OnWallCollisionOutside(collidedHull); - } - + } } else { @@ -280,9 +309,12 @@ namespace Barotrauma.Particles return; } if (Math.Abs(velocity.X) < 0.0001f && Math.Abs(velocity.Y) < 0.0001f) return; - + + //TODO: some better way to handle particle drag + //this doesn't work that well because the drag vector is only updated every 0.5 seconds, allowing the particle to accelerate way more than it should + //(e.g. a falling particle can freely accelerate for 0.5 seconds before the drag takes effect) dragWait--; - if (dragWait<=0) + if (dragWait <= 0) { dragWait = 30; diff --git a/Barotrauma/BarotraumaClient/Source/Particles/ParticleManager.cs b/Barotrauma/BarotraumaClient/Source/Particles/ParticleManager.cs index 75e3df2e7..2562abbda 100644 --- a/Barotrauma/BarotraumaClient/Source/Particles/ParticleManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Particles/ParticleManager.cs @@ -32,13 +32,11 @@ namespace Barotrauma.Particles this.cam = cam; particles = new Particle[MaxParticles]; - - LoadPrefabs(configFile); } - public void LoadPrefabs(string file) + public void LoadPrefabs() { - XDocument doc = XMLExtensions.TryLoadXml(file); + XDocument doc = XMLExtensions.TryLoadXml(ConfigFile); if (doc == null || doc.Root == null) return; prefabs = new Dictionary(); @@ -47,7 +45,7 @@ namespace Barotrauma.Particles { if (prefabs.ContainsKey(element.Name.ToString())) { - DebugConsole.ThrowError("Error in " + file + "! Each particle prefab must have a unique name."); + DebugConsole.ThrowError("Error in " + ConfigFile + "! Each particle prefab must have a unique name."); continue; } prefabs.Add(element.Name.ToString(), new ParticlePrefab(element)); diff --git a/Barotrauma/BarotraumaClient/Source/Particles/ParticlePrefab.cs b/Barotrauma/BarotraumaClient/Source/Particles/ParticlePrefab.cs index 6d9cf98aa..c9b00ea47 100644 --- a/Barotrauma/BarotraumaClient/Source/Particles/ParticlePrefab.cs +++ b/Barotrauma/BarotraumaClient/Source/Particles/ParticlePrefab.cs @@ -101,6 +101,20 @@ namespace Barotrauma.Particles } } + private Vector2 velocityChangeWater; + public Vector2 VelocityChangeWaterDisplay { get; private set; } + + [Editable(ToolTip = "How much the velocity of the particle changes per second when in water."), Serialize("0.0,0.0", false)] + public Vector2 VelocityChangeWater + { + get { return velocityChangeWater; } + private set + { + velocityChangeWater = value; + VelocityChangeWaterDisplay = ConvertUnits.ToDisplayUnits(value); + } + } + [Editable(0.0f, 10000.0f, ToolTip = "Drag applied to the particle when it's moving through water."), Serialize(0.0f, false)] public float CollisionRadius { get; private set; } @@ -164,6 +178,8 @@ namespace Barotrauma.Particles //---------------------------------------------------- + public readonly List SubEmitters = new List(); + public Dictionary SerializableProperties { get; @@ -191,9 +207,20 @@ namespace Barotrauma.Particles case "animatedsprite": Sprites.Add(new SpriteSheet(subElement)); break; + case "particleemitter": + case "emitter": + case "subemitter": + SubEmitters.Add(new ParticleEmitterPrefab(subElement)); + break; } } + //if velocity change in water is not given, it defaults to the normal velocity change + if (element.Attribute("velocitychangewater") == null) + { + VelocityChangeWater = VelocityChange; + } + if (element.Attribute("angularvelocity") != null) { AngularVelocityMin = element.GetAttributeFloat("angularvelocity", 0.0f); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/ParticleEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/ParticleEditorScreen.cs index 3e531ce7d..9c79b27a9 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/ParticleEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/ParticleEditorScreen.cs @@ -16,7 +16,9 @@ namespace Barotrauma { public float EmitTimer; - [Editable(), Serialize("0.0,0.0", false)] + public float BurstTimer; + + [Editable(), Serialize("0.0,360.0", false)] public Vector2 AngleRange { get; private set; } [Editable(), Serialize("0.0,0.0", false)] @@ -26,8 +28,12 @@ namespace Barotrauma public Vector2 ScaleRange { get; private set; } [Editable(), Serialize(0, false)] - public int ParticleAmount { get; private set; } - [Editable(), Serialize(0.0f, false)] + public int ParticleBurstAmount { get; private set; } + + [Editable(), Serialize(1.0f, false)] + public float ParticleBurstInterval { get; private set; } + + [Editable(), Serialize(1.0f, false)] public float ParticlesPerSecond { get; private set; } public string Name @@ -46,6 +52,11 @@ namespace Barotrauma public Emitter() { + ScaleRange = Vector2.One; + AngleRange = new Vector2(0.0f, 360.0f); + ParticleBurstAmount = 1; + ParticleBurstInterval = 1.0f; + SerializableProperties = SerializableProperty.GetProperties(this); } } @@ -210,6 +221,8 @@ namespace Barotrauma if (selectedPrefab != null) { emitter.EmitTimer += (float)deltaTime; + emitter.BurstTimer += (float)deltaTime; + if (emitter.ParticlesPerSecond > 0) { @@ -221,10 +234,15 @@ namespace Barotrauma } } - for (int i = 0; i < emitter.ParticleAmount; i++) + if (emitter.BurstTimer > emitter.ParticleBurstInterval) { - Emit(Vector2.Zero); + for (int i = 0; i < emitter.ParticleBurstAmount; i++) + { + Emit(Vector2.Zero); + } + emitter.BurstTimer = 0.0f; } + } GameMain.ParticleManager.Update((float)deltaTime);