Skip to content

Commit

Permalink
bring over particle system. (#76)
Browse files Browse the repository at this point in the history
* bring over particle system.

* added random class
  • Loading branch information
SatchelF authored Apr 11, 2024
1 parent 4b45e16 commit 0b05203
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 0 deletions.
75 changes: 75 additions & 0 deletions src/Client/Systems/MyRandom.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using Microsoft.Xna.Framework;

namespace CS5410
{
/// <summary>
/// Expands upon some of the features the .NET Random class does:
///
/// *NextRange : Generate a random number within some range
/// *NextGaussian : Generate a normally distributed random number
///
/// </summary>
class MyRandom : Random
{

/// <summary>
/// Generates a random number in the range or [Min,Max]
/// </summary>
public float nextRange(float min, float max)
{
return MathHelper.Lerp(min, max, (float)this.NextDouble());
}

/// <summary>
/// Generate a random vector about a unit circle
/// </summary>
public Vector2 nextCircleVector()
{
float angle = (float)(this.NextDouble() * 2.0 * Math.PI);
float x = (float)Math.Cos(angle);
float y = (float)Math.Sin(angle);

return new Vector2(x, y);
}

/// <summary>
/// Generate a normally distributed random number. Derived from a Wiki reference on
/// how to do this.
/// </summary>
public double nextGaussian(double mean, double stdDev)
{
if (this.usePrevious)
{
this.usePrevious = false;
return mean + y2 * stdDev;
}
this.usePrevious = true;

double x1 = 0.0;
double x2 = 0.0;
double y1 = 0.0;
double z = 0.0;

do
{
x1 = 2.0 * this.NextDouble() - 1.0;
x2 = 2.0 * this.NextDouble() - 1.0;
z = (x1 * x1) + (x2 * x2);
}
while (z >= 1.0);

z = Math.Sqrt((-2.0 * Math.Log(z)) / z);
y1 = x1 * z;
y2 = x2 * z;

return mean + y1 * stdDev;
}

/// <summary>
/// Keep this around to optimize gaussian calculation performance.
/// </summary>
private double y2;
private bool usePrevious { get; set; }
}
}
53 changes: 53 additions & 0 deletions src/Client/Systems/Particle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Microsoft.Xna.Framework;
using System;

namespace CS5410
{
public class Particle
{
public long name;
public Vector2 size;
public Vector2 center;
public float rotation;
public Color color; // Added color property

private Vector2 direction;
private float speed;
private TimeSpan lifetime;
private TimeSpan alive = TimeSpan.Zero;
private static long m_nextName = 0;

// Extended constructor to include color
public Particle(Vector2 center, Vector2 direction, float speed, Vector2 size, TimeSpan lifetime, Color initialColor)
{
this.name = m_nextName++;
this.center = center;
this.direction = direction;
this.speed = speed;
this.size = size;
this.lifetime = lifetime;
this.rotation = 0;
this.color = initialColor; // Initialize color
}

public bool update(GameTime gameTime)
{
// Update how long it has been alive
alive += gameTime.ElapsedGameTime;

// Update its center
center.X += (float)(gameTime.ElapsedGameTime.TotalMilliseconds * speed * direction.X);
center.Y += (float)(gameTime.ElapsedGameTime.TotalMilliseconds * speed * direction.Y);

// Rotate proportional to its speed
rotation += (speed / 0.5f);

// Example color fading logic: fade out by reducing the alpha value over time
float lifeFraction = (float)alive.TotalMilliseconds / (float)lifetime.TotalMilliseconds;
color = new Color(color.R, color.G, color.B, (byte)MathHelper.Clamp(255 * (1 - lifeFraction), 0, 255));

// Return true if this particle is still alive
return alive < lifetime;
}
}
}
135 changes: 135 additions & 0 deletions src/Client/Systems/ParticleSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;

namespace CS5410
{
public class ParticleSystem
{
private Dictionary<long, Particle> m_particles = new Dictionary<long, Particle>();
public Dictionary<long, Particle>.ValueCollection particles => m_particles.Values;
private MyRandom m_random = new MyRandom();

private Vector2 m_center;
private int m_sizeMean; // pixels
private int m_sizeStdDev; // pixels
private float m_speedMean; // pixels per millisecond
private float m_speedStDev; // pixels per millisecond
private float m_lifetimeMean; // milliseconds
private float m_lifetimeStdDev; // milliseconds

public ParticleSystem(Vector2 center, int sizeMean, int sizeStdDev, float speedMean, float speedStdDev, int lifetimeMean, int lifetimeStdDev)
{
m_center = center;
m_sizeMean = sizeMean;
m_sizeStdDev = sizeStdDev;
m_speedMean = speedMean;
m_speedStDev = speedStdDev;
m_lifetimeMean = lifetimeMean;
m_lifetimeStdDev = lifetimeStdDev;
}

public void ShipThrust(Vector2 landerCenter, Vector2 direction, float landerRotation, float landerSize)
{
Vector2 thrustOffset = new Vector2(0, landerSize / 2);

Matrix rotationMatrix = Matrix.CreateRotationZ(landerRotation);
thrustOffset = Vector2.Transform(thrustOffset, rotationMatrix);

Vector2 thrustStartPosition = landerCenter + thrustOffset;

Color[] particleColors = new Color[] { Color.Red, Color.Orange, Color.Yellow };

Vector2[] trianglePoints = new Vector2[]
{
new Vector2(-0.5f, 1),
new Vector2(0.5f, 1),
new Vector2(0, 0)
};

float triangleScale = 5.0f;

// Scale the triangle points
for (int i = 0; i < trianglePoints.Length; i++)
{
trianglePoints[i] *= triangleScale;
}


for (int i = 0; i < 20; i++)
{
float size = (float)m_random.nextGaussian(m_sizeMean, m_sizeStdDev);
size *= 4;

Color initialColor = particleColors[m_random.Next(particleColors.Length)];

Vector2 randomPoint = thrustStartPosition + trianglePoints[m_random.Next(trianglePoints.Length)];
Vector2 targetDirection = randomPoint - thrustStartPosition;


float angleVariation = MathHelper.ToRadians(10);
float randomAngle = (float)(m_random.NextDouble() * angleVariation - angleVariation / 2);
targetDirection = Vector2.Transform(targetDirection, Matrix.CreateRotationZ(randomAngle));

targetDirection.Y *= 1;

var particle = new Particle(
thrustStartPosition,
direction + targetDirection * 0.2f,
(float)m_random.nextGaussian(m_speedMean, m_speedStDev) * 0.5f,
new Vector2(size, size),
TimeSpan.FromMilliseconds(m_random.nextGaussian(m_lifetimeMean / 2, m_lifetimeStdDev / 2)),
initialColor
);
m_particles.Add(particle.name, particle);
}
}





public void ShipCrash(Vector2 position)
{
Color[] particleColors = { Color.Red, Color.Orange, Color.Yellow };
for (int i = 0; i < 500; i++)
{
float size = (float)m_random.nextGaussian(m_sizeMean, m_sizeStdDev);
Color initialColor = particleColors[m_random.Next(particleColors.Length)];
Vector2 direction = m_random.nextCircleVector() * 0.5f;

var particle = new Particle(
position,
direction, // Less spread out direction
(float)m_random.nextGaussian(m_speedMean, m_speedStDev) * 0.3f, // Slower speed for a more condensed effect
new Vector2(size, size),
TimeSpan.FromMilliseconds(m_random.nextGaussian(m_lifetimeMean, m_lifetimeStdDev)),
initialColor
);
m_particles.Add(particle.name, particle);
}
}




public void update(GameTime gameTime)
{

List<long> removeMe = new List<long>();
foreach (var p in m_particles.Values)
{
if (!p.update(gameTime))
{
removeMe.Add(p.name);
}
}


foreach (var key in removeMe)
{
m_particles.Remove(key);
}
}
}
}
46 changes: 46 additions & 0 deletions src/Client/Systems/ParticleSystemRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace CS5410
{
public class ParticleSystemRenderer
{
private string m_nameParticleContent;
private Texture2D m_texParticle;

public ParticleSystemRenderer(string nameParticleContent)
{
m_nameParticleContent = nameParticleContent;
}

public void LoadContent(ContentManager content)
{
m_texParticle = content.Load<Texture2D>(m_nameParticleContent);
}

public void draw(SpriteBatch spriteBatch, ParticleSystem system)
{

Vector2 origin = new Vector2(m_texParticle.Width / 2, m_texParticle.Height / 2);
foreach (Particle particle in system.particles)
{
// Scale the particle size relative to the texture size
Vector2 scale = new Vector2(particle.size.X / m_texParticle.Width, particle.size.Y / m_texParticle.Height);

spriteBatch.Draw(
m_texParticle,
particle.center,
null, // Full source rectangle
particle.color, // Use particle's color
particle.rotation,
origin, // Centered origin
scale, // Scale to particle size
SpriteEffects.None,
0);
}


}
}
}

0 comments on commit 0b05203

Please sign in to comment.