
// firework - Fireworks graphics
// Author: Po Shan Cheah
// Last updated: August 18, 2003
//
// Compile with: csc /doc:firework.xml /t:winexe firework.cs
namespace FireWork {
using System;
using System.Drawing;
using System.Windows.Forms;
/// <summary>Keeps track of one of the fireworks.</summary>
class FireWork {
/// <summary>Maximum number of rays</summary>
const int MaxRays = 10;
/// <summary>Where the rays begin.</summary>
double start;
/// <summary>Where the rays end.</summary>
double stop;
/// <summary>Maximum length of the rays.</summary>
double len;
/// <summary>Current position in the iteration.</summary>
double curpos;
SolidBrush brush;
/// <summary>Number of rays.</summary>
int nrays;
/// <summary>Center. X coord.</summary>
int cx;
/// <summary>Center. Y coord.</summary>
int cy;
/// <summary>Cached values of the sin of the angle of each
/// ray.</summary>
double[] sintab;
/// <summary>Cached values of the cos of the angle of each
/// ray.</summary>
double[] costab;
/// <summary>This determines how much faster each ray falls because of
/// gravity.</summary>
double descent;
static Random rand = new Random();
/// <summary>How much the fireworks should advance on each
/// step.</summary>
const double Step = 0.5;
/// <summary>Advance by one position.</summary>
/// <returns>False if this fireworks has gone away.</returns>
public bool Update() {
curpos += Step;
return curpos <= stop + len;
}
/// <summary>Paint this fireworks</summary>
/// <remarks>The fireworks should be drawn from max(curpos-len,start)
/// to min(curpos,stop).</remarks>
/// <param name="g">Graphics context</param>
public void Paint(Graphics g) {
double lower = Math.Max(curpos - len, start);
double upper = Math.Min(curpos, stop);
for (double pos = lower; pos < upper; pos += Step) {
// The quad squared component simulates some additional
// downward movement due to gravity.
double quad = descent * pos;
double quadsq = quad * quad;
for (int i = 0; i < nrays; ++i)
g.FillRectangle(brush,
(int) (cx + pos * costab[i]),
(int) (cy + pos * sintab[i] + quadsq),
1, 1);
}
} // Paint
/// <summary>Initialize fireworks.</summary>
/// <param name="xsize">Width of drawing area</param>
/// <param name="ysize">Height of drawing area</param>
public FireWork(int xsize, int ysize) {
cx = rand.Next(xsize);
cy = rand.Next(ysize);
descent = rand.NextDouble() * 0.1 + 0.05;
start = rand.NextDouble() * 10 + 5;
stop = rand.NextDouble() * 50 + 50;
len = rand.NextDouble() * 50 + 25;
curpos = start;
brush = new SolidBrush(Color.FromArgb(rand.Next(128, 256),
rand.Next(128, 256),
rand.Next(128, 256)));
nrays = rand.Next(5, MaxRays + 1);
double angleInc = 2 * Math.PI / nrays;
double angle = rand.NextDouble() * angleInc;
costab = new double[nrays];
sintab = new double[nrays];
for (int i = 0; i < nrays; ++i, angle += angleInc) {
costab[i] = Math.Cos(angle);
sintab[i] = Math.Sin(angle);
}
}
} // class FireWork
/// <summary>Tracks all the fireworks</summary>
class FireWorks : Form {
/// <summary>Maximum number of fireworks.</summary>
const int MaxFireWorks = 10;
FireWork[] fireworks = new FireWork[MaxFireWorks];
static Random rand = new Random();
/// <summary>Timer event handler. Will be called periodically to update
/// and redraw the fireworks.</summary>
void Tick(Object o, EventArgs e) {
// Update all fireworks.
for (int i = 0; i < MaxFireWorks; ++i)
if (fireworks[i] != null)
if (!fireworks[i].Update())
// If this fireworks has ended, remove it.
fireworks[i] = null;
// Create a new fireworks randomly if there's an open slot.
if (rand.Next(10) == 0)
for (int i = 0; i < MaxFireWorks; ++i)
if (fireworks[i] == null) {
fireworks[i] = new FireWork(ClientRectangle.Width,
ClientRectangle.Height);
break;
}
Invalidate();
// Invalidate() by itself does not trigger a repaint.
Update();
} // Tick
/// <summary>Paint event handler.</summary>
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.Clear(Color.Black);
foreach (FireWork fw in fireworks)
if (fw != null)
fw.Paint(e.Graphics);
}
/// <summary>Milliseconds between each update.</summary>
const int UpdateInterval = 25;
FireWorks() {
Text = "Fireworks";
Name = "Fireworks";
// Activate double-buffering.
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
ClientSize = new Size(700, 600);
// Create a timer for updating the display.
Timer timer = new Timer();
timer.Tick += new EventHandler(Tick);
timer.Interval = UpdateInterval;
timer.Start();
}
static int Main() {
Application.Run(new FireWorks());
return 0;
}
} // class FireWorks
} // namespace FireWork
// The End