diff options
Diffstat (limited to 'Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers')
19 files changed, 479 insertions, 0 deletions
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/AgeModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/AgeModifier.cs new file mode 100644 index 0000000..fac85f0 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/AgeModifier.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.ComponentModel; +using MonoGame.Extended.Particles.Modifiers.Interpolators; + +namespace MonoGame.Extended.Particles.Modifiers +{ + public class AgeModifier : Modifier + { + [EditorBrowsable(EditorBrowsableState.Always)] + public List<Interpolator> Interpolators { get; set; } = new List<Interpolator>(); + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + var n = Interpolators.Count; + while (iterator.HasNext) + { + var particle = iterator.Next(); + for (var i = 0; i < n; i++) + { + var interpolator = Interpolators[i]; + interpolator.Update(particle->Age, particle); + } + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/CircleContainerModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/CircleContainerModifier.cs new file mode 100644 index 0000000..30d2802 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/CircleContainerModifier.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Particles.Modifiers.Containers +{ + public class CircleContainerModifier : Modifier + { + public float Radius { get; set; } + public bool Inside { get; set; } = true; + public float RestitutionCoefficient { get; set; } = 1; + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + var radiusSq = Radius*Radius; + while (iterator.HasNext) + { + var particle = iterator.Next(); + var localPos = particle->Position - particle->TriggerPos; + + var distSq = localPos.LengthSquared(); + var normal = localPos; + normal.Normalize(); + + if (Inside) + { + if (distSq < radiusSq) continue; + + SetReflected(distSq, particle, normal); + } + else + { + if (distSq > radiusSq) continue; + + SetReflected(distSq, particle, -normal); + } + } + } + + private unsafe void SetReflected(float distSq, Particle* particle, Vector2 normal) + { + var dist = (float) Math.Sqrt(distSq); + var d = dist - Radius; // how far outside the circle is the particle + + var twoRestDot = 2*RestitutionCoefficient* + Vector2.Dot(particle->Velocity, normal); + particle->Velocity -= twoRestDot*normal; + + // exact computation requires sqrt or goniometrics + particle->Position -= normal*d; + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/RectangleContainerModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/RectangleContainerModifier.cs new file mode 100644 index 0000000..a56e072 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/RectangleContainerModifier.cs @@ -0,0 +1,59 @@ +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Particles.Modifiers.Containers +{ + public sealed class RectangleContainerModifier : Modifier + { + public int Width { get; set; } + public int Height { get; set; } + public float RestitutionCoefficient { get; set; } = 1; + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + while (iterator.HasNext) + { + var particle = iterator.Next(); + + var left = particle->TriggerPos.X + Width*-0.5f; + var right = particle->TriggerPos.X + Width*0.5f; + var top = particle->TriggerPos.Y + Height*-0.5f; + var bottom = particle->TriggerPos.Y + Height*0.5f; + + var xPos = particle->Position.X; + var xVel = particle->Velocity.X; + var yPos = particle->Position.Y; + var yVel = particle->Velocity.Y; + + if ((int) particle->Position.X < left) + { + xPos = left + (left - xPos); + xVel = -xVel*RestitutionCoefficient; + } + else + { + if (particle->Position.X > right) + { + xPos = right - (xPos - right); + xVel = -xVel*RestitutionCoefficient; + } + } + + if (particle->Position.Y < top) + { + yPos = top + (top - yPos); + yVel = -yVel*RestitutionCoefficient; + } + else + { + if ((int) particle->Position.Y > bottom) + { + yPos = bottom - (yPos - bottom); + yVel = -yVel*RestitutionCoefficient; + } + } + particle->Position = new Vector2(xPos, yPos); + particle->Velocity = new Vector2(xVel, yVel); + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/RectangleLoopContainerModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/RectangleLoopContainerModifier.cs new file mode 100644 index 0000000..4da6efa --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Containers/RectangleLoopContainerModifier.cs @@ -0,0 +1,42 @@ +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Particles.Modifiers.Containers +{ + public class RectangleLoopContainerModifier : Modifier + { + public int Width { get; set; } + public int Height { get; set; } + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + while (iterator.HasNext) + { + var particle = iterator.Next(); + var left = particle->TriggerPos.X + Width*-0.5f; + var right = particle->TriggerPos.X + Width*0.5f; + var top = particle->TriggerPos.Y + Height*-0.5f; + var bottom = particle->TriggerPos.Y + Height*0.5f; + + var xPos = particle->Position.X; + var yPos = particle->Position.Y; + + if ((int) particle->Position.X < left) + xPos = particle->Position.X + Width; + else + { + if ((int) particle->Position.X > right) + xPos = particle->Position.X - Width; + } + + if ((int) particle->Position.Y < top) + yPos = particle->Position.Y + Height; + else + { + if ((int) particle->Position.Y > bottom) + yPos = particle->Position.Y - Height; + } + particle->Position = new Vector2(xPos, yPos); + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/DragModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/DragModifier.cs new file mode 100644 index 0000000..f2d6d09 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/DragModifier.cs @@ -0,0 +1,23 @@ +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Particles.Modifiers +{ + public class DragModifier : Modifier + { + public float DragCoefficient { get; set; } = 0.47f; + public float Density { get; set; } = .5f; + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + while (iterator.HasNext) + { + var particle = iterator.Next(); + var drag = -DragCoefficient*Density*particle->Mass*elapsedSeconds; + + particle->Velocity = new Vector2( + particle->Velocity.X + particle->Velocity.X*drag, + particle->Velocity.Y + particle->Velocity.Y*drag); + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/ColorInterpolator.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/ColorInterpolator.cs new file mode 100644 index 0000000..f94c689 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/ColorInterpolator.cs @@ -0,0 +1,13 @@ +namespace MonoGame.Extended.Particles.Modifiers.Interpolators +{ + /// <summary> + /// Defines a modifier which interpolates the color of a particle over the course of its lifetime. + /// </summary> + public sealed class ColorInterpolator : Interpolator<HslColor> + { + public override unsafe void Update(float amount, Particle* particle) + { + particle->Color = HslColor.Lerp(StartValue, EndValue, amount); + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/HueInterpolator.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/HueInterpolator.cs new file mode 100644 index 0000000..8b58a8e --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/HueInterpolator.cs @@ -0,0 +1,12 @@ +using MonoGame.Extended; + +namespace MonoGame.Extended.Particles.Modifiers.Interpolators +{ + public class HueInterpolator : Interpolator<float> + { + public override unsafe void Update(float amount, Particle* particle) + { + particle->Color = new HslColor((EndValue - StartValue) * amount + StartValue, particle->Color.S, particle->Color.L); + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/Interpolator.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/Interpolator.cs new file mode 100644 index 0000000..0ec9866 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/Interpolator.cs @@ -0,0 +1,26 @@ +namespace MonoGame.Extended.Particles.Modifiers.Interpolators +{ + public abstract class Interpolator + { + protected Interpolator() + { + Name = GetType().Name; + } + + public string Name { get; set; } + public abstract unsafe void Update(float amount, Particle* particle); + } + + public abstract class Interpolator<T> : Interpolator + { + /// <summary> + /// Gets or sets the intial value when the particles are created. + /// </summary> + public virtual T StartValue { get; set; } + + /// <summary> + /// Gets or sets the final value when the particles are retired. + /// </summary> + public virtual T EndValue { get; set; } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/OpacityInterpolator.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/OpacityInterpolator.cs new file mode 100644 index 0000000..0a26fcd --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/OpacityInterpolator.cs @@ -0,0 +1,10 @@ +namespace MonoGame.Extended.Particles.Modifiers.Interpolators +{ + public class OpacityInterpolator : Interpolator<float> + { + public override unsafe void Update(float amount, Particle* particle) + { + particle->Opacity = (EndValue - StartValue) * amount + StartValue; + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/RotationInterpolator.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/RotationInterpolator.cs new file mode 100644 index 0000000..44a72de --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/RotationInterpolator.cs @@ -0,0 +1,10 @@ +namespace MonoGame.Extended.Particles.Modifiers.Interpolators +{ + public class RotationInterpolator : Interpolator<float> + { + public override unsafe void Update(float amount, Particle* particle) + { + particle->Rotation = (EndValue - StartValue) * amount + StartValue; + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/ScaleInterpolator.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/ScaleInterpolator.cs new file mode 100644 index 0000000..aff9244 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/ScaleInterpolator.cs @@ -0,0 +1,12 @@ +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Particles.Modifiers.Interpolators +{ + public class ScaleInterpolator : Interpolator<Vector2> + { + public override unsafe void Update(float amount, Particle* particle) + { + particle->Scale = (EndValue - StartValue) * amount + StartValue; + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/VelocityInterpolator b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/VelocityInterpolator new file mode 100644 index 0000000..bad04b1 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Interpolators/VelocityInterpolator @@ -0,0 +1,12 @@ +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Particles.Modifiers.Interpolators +{ + public class VelocityInterpolator : Interpolator<Vector2> + { + public override unsafe void Update(float amount, Particle* particle) + { + particle->Velocity = (EndValue - StartValue) * amount + StartValue; + } + } +} diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/LinearGravityModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/LinearGravityModifier.cs new file mode 100644 index 0000000..e9ed216 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/LinearGravityModifier.cs @@ -0,0 +1,23 @@ +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Particles.Modifiers +{ + public class LinearGravityModifier : Modifier + { + public Vector2 Direction { get; set; } + public float Strength { get; set; } + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + var vector = Direction*(Strength*elapsedSeconds); + + while (iterator.HasNext) + { + var particle = iterator.Next(); + particle->Velocity = new Vector2( + particle->Velocity.X + vector.X*particle->Mass, + particle->Velocity.Y + vector.Y*particle->Mass); + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Modifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Modifier.cs new file mode 100644 index 0000000..bd62d25 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/Modifier.cs @@ -0,0 +1,18 @@ +namespace MonoGame.Extended.Particles.Modifiers +{ + public abstract class Modifier + { + protected Modifier() + { + Name = GetType().Name; + } + + public string Name { get; set; } + public abstract void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator); + + public override string ToString() + { + return $"{Name} [{GetType().Name}]"; + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/OpacityFastFadeModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/OpacityFastFadeModifier.cs new file mode 100644 index 0000000..9cc44d8 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/OpacityFastFadeModifier.cs @@ -0,0 +1,14 @@ +namespace MonoGame.Extended.Particles.Modifiers +{ + public sealed class OpacityFastFadeModifier : Modifier + { + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + while (iterator.HasNext) + { + var particle = iterator.Next(); + particle->Opacity = 1.0f - particle->Age; + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/RotationModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/RotationModifier.cs new file mode 100644 index 0000000..2b17058 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/RotationModifier.cs @@ -0,0 +1,18 @@ +namespace MonoGame.Extended.Particles.Modifiers +{ + public class RotationModifier : Modifier + { + public float RotationRate { get; set; } + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + var rotationRateDelta = RotationRate*elapsedSeconds; + + while (iterator.HasNext) + { + var particle = iterator.Next(); + particle->Rotation += rotationRateDelta; + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VelocityColorModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VelocityColorModifier.cs new file mode 100644 index 0000000..ae9dc7b --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VelocityColorModifier.cs @@ -0,0 +1,36 @@ +using System; + +namespace MonoGame.Extended.Particles.Modifiers +{ + public class VelocityColorModifier : Modifier + { + public HslColor StationaryColor { get; set; } + public HslColor VelocityColor { get; set; } + public float VelocityThreshold { get; set; } + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + var velocityThreshold2 = VelocityThreshold*VelocityThreshold; + + while (iterator.HasNext) + { + var particle = iterator.Next(); + var velocity2 = particle->Velocity.X*particle->Velocity.X + + particle->Velocity.Y*particle->Velocity.Y; + var deltaColor = VelocityColor - StationaryColor; + + if (velocity2 >= velocityThreshold2) + VelocityColor.CopyTo(out particle->Color); + else + { + var t = (float) Math.Sqrt(velocity2)/VelocityThreshold; + + particle->Color = new HslColor( + deltaColor.H*t + StationaryColor.H, + deltaColor.S*t + StationaryColor.S, + deltaColor.L*t + StationaryColor.L); + } + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VelocityModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VelocityModifier.cs new file mode 100644 index 0000000..f089abc --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VelocityModifier.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using MonoGame.Extended.Particles.Modifiers.Interpolators; + +namespace MonoGame.Extended.Particles.Modifiers +{ + public class VelocityModifier : Modifier + { + public List<Interpolator> Interpolators { get; set; } = new List<Interpolator>(); + + public float VelocityThreshold { get; set; } + + public override unsafe void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + var velocityThreshold2 = VelocityThreshold*VelocityThreshold; + var n = Interpolators.Count; + + while (iterator.HasNext) + { + var particle = iterator.Next(); + var velocity2 = particle->Velocity.LengthSquared(); + + if (velocity2 >= velocityThreshold2) + { + for (var i = 0; i < n; i++) + { + var interpolator = Interpolators[i]; + interpolator.Update(1, particle); + } + } + else + { + var t = (float) Math.Sqrt(velocity2)/VelocityThreshold; + for (var i = 0; i < n; i++) + { + var interpolator = Interpolators[i]; + interpolator.Update(t, particle); + } + } + } + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VortexModifier.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VortexModifier.cs new file mode 100644 index 0000000..03a9999 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Particles/Modifiers/VortexModifier.cs @@ -0,0 +1,30 @@ +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Particles.Modifiers +{ + public unsafe class VortexModifier : Modifier + { + // Note: not the real-life one + private const float _gravConst = 100000f; + + public Vector2 Position { get; set; } + public float Mass { get; set; } + public float MaxSpeed { get; set; } + + public override void Update(float elapsedSeconds, ParticleBuffer.ParticleIterator iterator) + { + while (iterator.HasNext) + { + var particle = iterator.Next(); + var diff = Position + particle->TriggerPos - particle->Position; + + var distance2 = diff.LengthSquared(); + + var speedGain = _gravConst*Mass/distance2*elapsedSeconds; + // normalize distances and multiply by speedGain + diff.Normalize(); + particle->Velocity += diff*speedGain; + } + } + } +}
\ No newline at end of file |