
// worms - Moving worms animation
// Author: Po Shan Cheah
// Last updated: August 27, 2003
//
// Compile with: csc /t:winexe /doc:worms.xml worms.cs
namespace Worms {
using System;
using System.Drawing;
using System.Windows.Forms;
/// <summary>Keeps track of one worm</summary>
class Worm {
Point[] points;
/// <summary>Width of the drawing area</summary>
int xsize;
/// <summary>Height of the drawing area</summary>
int ysize;
/// <summary>The current tail of the worm. The next segment will be
/// added after this one.</summary>
int tail = 0;
Pen pen;
/// <summary>Current direction of travel for the worm in
/// radians.</summary>
double dir = 0;
/// <summary>Angle of the worm's direction change on each round in
/// radians.</summary>
const double DirChange = 0.2;
/// <summary>Distance the worm will move on each round.</summary>
const int WormShift = 6;
/// <summary>Radius of each worm segment.</summary>
const int WormRadius = 4;
/// <summary>Worm length</summary>
const int WormLength = 25;
static Random rand = new Random();
/// <summary>Constructor for the worm</summary>
/// <param name="xsize">Width of drawing area</param>
/// <param name="ysize">Height of drawing area</param>
public Worm(int xsize, int ysize) {
this.xsize = xsize;
this.ysize = ysize;
points = new Point[WormLength];
// Choose a random color for this worm.
pen = new Pen(Color.FromArgb(rand.Next(128, 256),
rand.Next(128, 256),
rand.Next(128, 256)));
// Need to start the worm with at least one segment.
points[tail] = new Point(rand.Next(xsize), rand.Next(ysize));
}
/// <summary>Adjust x so that it is between 0 and upper.</summary>
/// <remarks>If x is greater than upper, it will wrap to 0.
/// If x is less than zero, it will wrap to upper.</remarks>
/// <param name="x">value to wrap</param>
/// <param name="upper">upper upper bound of the range</param>
/// <returns>wrapped value</returns>
public int Wrap(int x, int upper) {
return x < 1 ? upper : x > upper ? 1 : x;
}
/// <summary>Generates a new worm segment.</summary>
/// <remarks>The direction of travel will be dir plus or minus
/// DirChange. The worm will wrap around the screen if
/// necessary.</remarks>
public void NewSegment() {
int nextTail = (tail + 1) % WormLength;
dir += rand.NextDouble() >= 0.5 ? DirChange : -DirChange;
points[nextTail] =
new Point(Wrap(points[tail].X +
(int) Math.Round(WormShift * Math.Cos(dir)),
xsize),
Wrap(points[tail].Y +
(int) Math.Round(WormShift * Math.Sin(dir)),
ysize));
tail = nextTail;
} // NewSegment
/// <summary>Draw the worm using the specified graphics context.</summary>
/// <param name="g">graphics context</param>
public void Paint(Graphics g) {
foreach (Point p in points)
if (!p.IsEmpty)
g.DrawEllipse(pen,
p.X - WormRadius, p.Y - WormRadius,
2 * WormRadius, 2 * WormRadius);
}
} // class Worm
/// <summary>Manages all the worms</summary>
class Worms : Form {
/// <summary>Number of worms</summary>
const int NWorms = 10;
Worm[] worms;
/// <summary>Paint event handler.</summary>
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.FillRectangle(Brushes.Black, 0, 0,
ClientRectangle.Width,
ClientRectangle.Height);
foreach (Worm w in worms)
w.Paint(e.Graphics);
}
/// <summary>Timer event handler. Will be called periodically to move
/// the worms and redraw the image.</summary>
void Tick(Object o, EventArgs e) {
foreach (Worm w in worms)
w.NewSegment();
Invalidate();
// Invalidate() by itself does not trigger a repaint.
Update();
}
/// <summary>Milliseconds between each round of worm
/// movement.</summary>
const int UpdateInterval = 200;
Worms() {
Text = "Worms";
Name = "Worms";
// Activate double-buffering.
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
ClientSize = new Size(700, 600);
worms = new Worm[NWorms];
for (int i = 0; i < NWorms; ++i)
worms[i] = new Worm(ClientRectangle.Width, ClientRectangle.Height);
// Create a timer for moving the worms and updating the display.
Timer timer = new Timer();
timer.Tick += new EventHandler(Tick);
timer.Interval = UpdateInterval;
timer.Start();
}
static int Main() {
Application.Run(new Worms());
return 0;
}
} // class Worms
}
// The End