Click here to Skip to main content
15,892,643 members
Articles / Programming Languages / C#

C# Asteroids without DirectX

Rate me:
Please Sign up or sign in to vote.
3.10/5 (10 votes)
27 Mar 200211 min read 193.8K   2.3K   31  
An implementation of the classic asteroids game using 2D Drawing classes
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
//using System.Runtime.InteropServices;
//using System.Threading;
using System.IO;


// Code and comments written / collated by Jason King (jason.king@profox.co.uk), Jan, Feb and Mar 2002.
// Many thanks to Jerzy Peter and Peter Stephens who contributed to answers regarding
// playing sounds using winmm.dll.
// Thanks also to the guys who tried to help with the background of images problem.
namespace Asteroids
{
	

	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class Form1 : System.Windows.Forms.Form
	{
		private System.ComponentModel.IContainer components;
		private System.Windows.Forms.Timer timer1;
		private Asteroids.PlayingField display;

		public Form1()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();
		
			this.BackColor = Color.Black;

			display = new PlayingField(timer1, new Point(0,0),this.Size);
			Controls.Add(display);
			timer1.Enabled = true;

		
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}


		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.timer1 = new System.Windows.Forms.Timer(this.components);
			// 
			// timer1
			// 
			this.timer1.Interval = 40;
			this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
			// 
			// Form1
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
			this.ClientSize = new System.Drawing.Size(704, 495);
			this.KeyPreview = true;
			this.Name = "Form1";
			this.Text = "Form1";
			this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
			this.Resize += new System.EventHandler(this.Form1_Resize);
			this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress);
			this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new Form1());
		}

	

		private void timer1_Tick(object sender, System.EventArgs e)
		{
			
			//		these next lines are now redundant as the playingfield now listens for the tick event
			
			//			for (int i=0; i<=display.playerArray.GetLength(0)-1; i++)
			//				{
			//					if (display.playerArray[i]!=null)
			//						if (display.playerArray[i].make_move())
			//						{
			//							display.playerArray[i] = null;
			//						}
			//
			//				}
			//	
			//			display.Refresh();
			//			display.check_collision();
		}

		

		private void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			
			// these are some special keys - N to make a new ship, P to pause the game, A to make a new sheet of asteroids
			switch (e.KeyCode)
			{
				case (Keys.N):

					if (display.theShip==null)
						display.makeShip();
				
					break;

				case (Keys.P):
					timer1.Enabled = !timer1.Enabled;
					break;

				case (Keys.A):
					display.makeAsteroids();
					break;
			}
			
			// forward all other key presses to the keyboard handling routines
			if (display.theShip!=null)
				display.theShip.setKeys(e);
			
			
		}

				
		
		private void Form1_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			// forward all the key releases to the keyhandling routines
			if (display.theShip!=null)
				display.theShip.releaseKeys(e);
		}
		
		
		
		private void Form1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
		{
			// a special key press - this is to cope with the rapid tapping of the fire key
			if (Char.ToString(e.KeyChar) == "k")
				if (display.theShip!=null)
					display.theShip.singleShot();
					
		}


		
		private void Form1_Resize(object sender, System.EventArgs e)
		{
			if (this.display!=null)
				this.display.Size = this.Size;
		}

		#region some code to test copying of files using file.copy versus filestream writing
		//		private void button1_Click_3(object sender, System.EventArgs e)
		//		{
		//			// it can be seen from the tests performed here that there is little
		//			// difference between copying files using file.copy
		//			// and copying the contents of a file stream to a new file.
		//			
		//			int numOfCopies = 100;
		//			timer1.Enabled = false;
		//			DateTime t1 = System.DateTime.Now;
		//			for(int i=0;i<=numOfCopies;i++)
		//				File.Copy("c:\\temp\\player_missile.wav", "c:\\temp\\p" + i.ToString()+".wav");
		//			DateTime t2 = System.DateTime.Now;
		//			TimeSpan snout = t2-t1;
		//			MessageBox.Show("Files:"+snout.TotalSeconds.ToString());
		//			DateTime t3 = System.DateTime.Now;
		//			FileStream myFileStream = new FileStream("c:\\temp\\player_missile.wav",FileMode.Open, FileAccess.Read );
		//			byte[] buffer = new Byte[myFileStream.Length];
		//			myFileStream.Read(buffer,0,(int)myFileStream.Length);
		//			FileStream myOutStream;
		//			for (int j=0; j<=numOfCopies;j++)
		//			{
		//				myOutStream = new FileStream("c:\\temp\\p" + j.ToString() + ".wav",FileMode.Create, FileAccess.Write);
		//				myOutStream.Write(buffer,0,(int)myFileStream.Length);
		//				myOutStream.Close();
		//			}
		//						 DateTime t4 = System.DateTime.Now;
		//						TimeSpan snout2 = t4-t3;
		//						MessageBox.Show("Stream:" + snout2.TotalSeconds.ToString());
		//		}
		#endregion

		

		
		
	}


	public class Player : UserControl
	{
		public int score = 0;
		public Point[] shapeArray;  // used for defining the shape that will be drawn - also used for collision detection
		public int incX, incY;  // the amount to offset this player by when it moves
		public Color myColor; // the default colour for this player.  This may be overriden in the animate methods
		public PlayingField myField; // a reference to the control that will draw the player
		public Region myRegion; // a region used in the collision detection.  Or not.  May not be used anymore.
		public GraphicsPath myPath; // the graphics path used for collision detection
		public object[,] animationArray; // a 2D array filled with [GraphicsPath, Pen | Brush]
		public string[] destroysClass; // a string array that defines which classes this instance can destroy when a collision is detected
		public string className;  // use in conjunctin with destroysClass for collision detection
		public string lastKeyPressed; 
		public Color[] possibleColors; // an array of colours that can be used for randomising the colour of the instance
		public Player myOwner; // used by missiles for determining who gets score allocated in the event of a collision with a scorable object.  Somewhat redundant in this code as there is only ever one player, however, this does allow for UFOs to fire missiles that can destroy asteroids, or for a second player at the same time
		public int MyIndexInOwnerArray = 0;  // used by the playingfield to determine which object to release
		protected string createSound, killSound;  //filenames
		protected string soundPath = "d:\\my documents\\Visual Studio Projects\\asteroids\\Asteroids\\"; // root path to the sound files
		
		public Player(PlayingField thePlayingField)
		{
			myField = thePlayingField;
			//register this as a listener or subscriber to the tick event of the playingfield clock
			myField.Timer.Tick += new System.EventHandler(this.game_Tick);
			
		}

		public virtual void launchMissile()
		{
		}
		public virtual void singleShot()
		{
		}
		
		//Define an event to be raised when this instance is ready for destruction
		public event DeathHandler OnDeath;

		public delegate void DeathHandler(Player thePlayer, System.EventArgs e);

		private void game_Tick(object sender, System.EventArgs e)
		{
			this.make_move();
			this.animate();
		}

		public virtual void animate()
		{
			// first up, make a copy of the shape array.
			Point[] tempPoints = new Point[this.shapeArray.GetLength(0)];
			Array.Copy(this.shapeArray,tempPoints,this.shapeArray.GetLength(0));

			// now translate this copy from its origins of 0,0 (relative to itself, not the screen)
			// to where this object actually is on the screen
			for (int i=0; i<=this.shapeArray.GetLength(0)-1; i++)
				tempPoints[i].Offset(this.Location.X, this.Location.Y);

			// now create the graphics path for this object and stick it into 
			// the animation array along with a brush or pen for filling / drawing with
			Brush myBrush = new SolidBrush(myColor);
			myPath = new GraphicsPath();
			myPath.AddPolygon(tempPoints);

			animationArray = new Object[1,2];
			animationArray[0,0] = myPath;
			animationArray[0,1] = myBrush;
		}

	
		
		public virtual void playMySound(string filename)
		{
			myField.PlaySound(soundPath + filename);
		}
		
		
		
		
		public virtual void setKeys(KeyEventArgs e)
		{
		}
		
		
		
		public virtual void releaseKeys(KeyEventArgs e)
		{
		}

		
		
		
		public virtual void killMe(Player owner)
		{
			// this is crucial - if you don't unsubscribe as a listener, then the clock
			// will retain a reference to this instance
			myField.Timer.Tick -= new System.EventHandler(this.game_Tick);
			if (OnDeath !=null)
				OnDeath(this, new System.EventArgs());
		}
		
		
		
		public virtual void killMe()
		{
			myField.Timer.Tick -= new System.EventHandler(this.game_Tick);
			
		}


		public virtual void beforeDeath(Player owner)
		{
		}

		
		public virtual void make_move()
		{
			int x = this.Location.X + incX;
			int y = this.Location.Y + incY;
			
			if (myField.bounce) // pinball mode - all players bounce of edges of playing field
			{

				if (x <= 0)
					// we are hitting the left hand edge of the screen
					// so we need to reverse the x direction
				{
					this.incX *=-1; // this bit reverses x direction
					this.incY -=1; // this bit just changes the angle slightly
				}
					
				if (x+this.Width >= myField.Width)
				{
					this.incX *=-1;
					this.incY +=1;
				}

				if (y  <= 0)
				{
					this.incY *=-1;
					this.incX +=1;

				}
				if (y + this.Width >= myField.Height)
				{
					this.incY *=-1;
					this.incX -=1;
				}
			
			}
			else // wrap around mode - go off one side and back on the other side
			{

				// now make sure that the new location fits on the screen -
				// if it goes off one side of the screen, it should come back
				// on the other.

				if (x + this.Width < 0)
					x = myField.Width;
				if (x > myField.Width)
					x = 1;; //0 - (int)this.Width/2;

				if (y + this.Height < 0)
					y = myField.Height;
				if (y > myField.Height)
					y = 1;//0 - (int)this.Height/2;

			}

			this.Location = new Point(x,y);

		}



	}

	public class particle : Player
	{
		public int timeOut; // = 3000;
		public int fader = 255;
		public int timeoutCounter = 0;

		public particle(Point myPoint, PlayingField theField): base(theField)
		{
			timeOut = (int)(theField.randomGenerator.NextDouble() * 5000) + 1;
			Color[] possibleColors;
			possibleColors = new Color[15]
				{
					Color.BlueViolet,
					Color.Crimson,
					Color.Red,
					Color.Yellow,
					Color.ForestGreen,
					Color.Azure, 
					Color.Chartreuse, 
					Color.Gold, 
					Color.DeepPink, 
					Color.Azure,
					Color.DarkGoldenrod,
					Color.DarkSalmon,
					Color.DarkTurquoise,
					Color.Purple,
					Color.Lavender  };
			possibleColors = new Color[11]
				{
					Color.DarkGreen,
					Color.DarkSeaGreen,
					Color.Green,
					Color.LawnGreen,
					Color.LightGreen,
					Color.ForestGreen,
					Color.LimeGreen,
					Color.Lime,
					Color.SpringGreen,
					Color.PaleGreen,
					Color.SeaGreen
				};
			// Lime is the colour that really shows up against a black background
			possibleColors = new Color[3]
				{
					Color.Red,
					Color.Yellow,
					Color.Red
				};
			//					Color.LimeGreen,
			//					Color.LimeGreen,
			//					Color.LimeGreen,
			//					Color.LimeGreen,
			//					Color.LightGreen,
			//					Color.LimeGreen
			//				};
			//				


			int colorIndex = (int)(myField.randomGenerator.NextDouble() * (possibleColors.GetLength(0)-1)) + 1;
			myColor = Color.FromArgb(254, possibleColors[colorIndex]);
			
			
			this.Location = myPoint;
			//myColor = Color.Lime;
			this.className = "particle";
			this.destroysClass = new string[1]{" "};

			
		}
		public override void make_move()
		{
			this.incX = (int)(myField.randomGenerator.NextDouble() * 2) + 1;
			this.incY = (int)(myField.randomGenerator.NextDouble() * 2) + 1;
			//			this.incY = -1;
			if ((int)(myField.randomGenerator.NextDouble() * 10) + 1 >5)
				this.incY  = this.incY * - 1;
			if ((int)(myField.randomGenerator.NextDouble() * 10) + 1 >5)
				this.incX = this.incX * -1;
			base.make_move();
		}
		public override void animate()
		{
			
			fader -=2;
			timeoutCounter += this.myField.Timer.Interval;
			if ( (fader < 0) | (timeoutCounter >= this.timeOut))
			{
				this.killMe(this);
				return;
			}

			Brush myBrush = new SolidBrush(Color.FromArgb(fader,myColor));
			myPath = new GraphicsPath();
			this.myPath.AddEllipse(this.Location.X,this.Location.Y,3,3);

			animationArray = new Object[1,2];
			animationArray[0,0] = myPath;
			animationArray[0,1] = myBrush;
			

		}


	}

	public class Asteroid : Player
	{
		private int spawnsOnDeath; // how many asteroids does this create when it is destroyed - big asteroids produce 3 mediums, medium asteroids produce 2 smalls, smalls produce no asteroids at all (but a nice sparkly particle effect!)
		private int fader = 0;
		private int invincibleCounter = 0;  // used to determine how long an asteroid is impervious to other asteroids during suicide mode

		public Asteroid(Point startPoint, int Xinc, int Yinc,  PlayingField Field, int spawn):base(Field)
		{
			
			switch (spawn)
			{
				case (3):
					this.killSound = "bigasteroid.wav";
					break;
				case (2):
					this.killSound = "mediumasteroid.wav";
					break;
				case (1):
					this.killSound = "smallasteroid.wav";
					break;
			}

			
			spawnsOnDeath = spawn;
			className = "Asteroid";
			destroysClass = new String[3];
			destroysClass[0] = "Ship";
			destroysClass[1] = "Missile";

			if (myField.suicide)
				destroysClass[2] = "Asteroid"; //this means that an asteroid may destroy another asteroid
			
			else
				destroysClass[2] = "   "; // just a cludge to avoid having to redefine the array to be just 2 elements
			
		
			myField = Field;
			this.Location = startPoint;
			// the x and y increments are random.  By adding (3-spawn) to the increments, we force the smaller asteroids
			// to tend towards being faster than bigger asteroids, though not necessarily.  We need not do this at all
			this.incX = Xinc + (3-spawn);  
			this.incY = Yinc + (3-spawn); 
			
			// big asteroids have a score of 10, mediums have 20, smalls have 30
			this.score = (4-spawn) * 10; 
			
			// just make sure that all the randomness doesn't result in a stationary asteroid
			// it has happened!
			if ((this.incX ==0) & (this.incY==0))
			{
				//MessageBox.Show("Magic stationary asteroid");
				this.incX = this.incY = 1;
			}

			possibleColors = new Color[15]
				{
					Color.BlueViolet,
					Color.Crimson,
					Color.Red,
					Color.Yellow,
					Color.Lime,
					Color.Azure, 
					Color.Chartreuse, 
					Color.Gold, 
					Color.DeepPink, 
					Color.Azure,
					Color.DarkGoldenrod,
					Color.DarkSalmon,
					Color.DarkTurquoise,
					Color.Purple,
					Color.Lavender  };
			int colorIndex = (int)(myField.randomGenerator.NextDouble() * (possibleColors.GetLength(0)-1)) + 1;
			myColor = Color.FromArgb(200, possibleColors[colorIndex]);
				
			//use the colorIndex as a radom amount to offset the asteroids points by for some variation
				
			colorIndex = colorIndex * 2;
			shapeArray = new Point[15];
			shapeArray[0] = new Point(colorIndex+30,10);
			shapeArray[1] = new Point(50+colorIndex,20+colorIndex);
			shapeArray[2] = new Point(90+colorIndex,15+colorIndex);
			shapeArray[3] = new Point(100+colorIndex,23+colorIndex);
			shapeArray[4] = new Point(100+colorIndex,40+colorIndex);
			shapeArray[5] = new Point(92+colorIndex,55+colorIndex);
			shapeArray[6] = new Point(100+colorIndex,64+colorIndex);
			shapeArray[7] = new Point(85+colorIndex,85+colorIndex);
			shapeArray[8] = new Point(50+colorIndex,90+colorIndex);
			shapeArray[9] = new Point(30+colorIndex,81+colorIndex);
			shapeArray[10] = new Point(20+colorIndex,70+colorIndex);
			shapeArray[11] = new Point(30+colorIndex,50+colorIndex);
			shapeArray[12] = new Point(8+colorIndex,38+colorIndex);
			shapeArray[13] = new Point(10+colorIndex,20+colorIndex);
			shapeArray[14] = new Point(20+colorIndex,15+colorIndex);
			
		
			// now perform a random rotation on the points for variety
			// for the rotation angle, we'll just use the x coordinate,
			// actually, now we have a random generator, lets use that

			// change the size depending how many asteroids this asteroid will spawn
			float sizeFactor = (float)spawnsOnDeath/3;
			this.Size = new Size((int)(this.Width*sizeFactor),(int)(this.Height*sizeFactor));

			Matrix myMatrix = new Matrix();
			myMatrix.Scale(sizeFactor,sizeFactor);
			Point asteroidCenter = new Point((int)this.Width/2, (int)this.Height/2);
			myMatrix.RotateAt((int)(myField.randomGenerator.NextDouble()*360), asteroidCenter, MatrixOrder.Append);
			myMatrix.TransformPoints(shapeArray);
		}

		public override void make_move()
		{
			base.make_move();
			
			if (myField.suicide) // if we are in suicide mode (asteroids may destroy each other)
				// so make sure that each asteroid is invincible for about 3 seconds
				// this allows an asteroid to spawn its children without them immediately
				// killing each other.  It gives em time to move away from each other.
			{
				if (this.invincibleCounter<=3000)
				{	
					invincibleCounter +=this.myField.Timer.Interval;
					this.destroysClass[2] = "  ";
				}
 			
				if (invincibleCounter >= 3000)
					this.destroysClass[2] = "Asteroid";
			}
			

		}

	
		public override void beforeDeath(Player collidedWith)
		{
			
			this.playMySound(killSound);

			// when a fatal collision is detected, the object that this instance collides with
			// is passed in (as you can see above).  This allows this instance to increment the
			// the score of whoever owned the thing this is collided with (try reading that again).

			// if the other party (missile?) in this collision has an owner (human player?)
			// then increments its score
			if (collidedWith.myOwner!=null)
				collidedWith.myOwner.score += this.score;
			int Xinc, Yinc;
			// get our ramdom directions
	
			if (spawnsOnDeath > 1)  // spawnsOnDeath is 1, then this is a small asteroid which does not spawn any more
			{
				for (int i=1; i<= spawnsOnDeath; i++)
				{
					Xinc = (int)(4-spawnsOnDeath + myField.randomGenerator.NextDouble() * 4);
					Yinc = (int)(4-spawnsOnDeath + myField.randomGenerator.NextDouble() * 4);
			
					// make sure we have some that go right to left and bottom to top
					if (myField.randomGenerator.NextDouble() > 0.5)
						Xinc = Xinc * -1;
					if (myField.randomGenerator.NextDouble() > 0.5)
						Yinc = Yinc * -1;

					myField.addPlayer(new Asteroid(this.Location,Xinc, Yinc, myField, spawnsOnDeath-1));
				}
			}
			else
				// add some particles when the last asteroid is killed
				myField.spawnParticles(10,this.Location);
		}

	}
	
	public class Missile:Player
	{
		protected Point StartPoint;
		protected int distanceMoved;
		
		//private SoundPlayer player;
	
		public Missile(Point startPoint, int Xinc, int Yinc,  PlayingField Field, Player owner):base(Field)
		{
			
			createSound = "player_missile.wav"; 	
			//			if (createSound==null)
			//				createSound ="player_missile.wav";
			//PlaySound(soundPath + createSound, 0, PlaySoundFlag.Filename|PlaySoundFlag.Asynchronously); 
			
			
			myOwner = owner;
			StartPoint = startPoint;
			destroysClass = new String[1];
			//destroysClass[0] = "Ship";
			destroysClass[0] = "Asteroid";
			className = "Missile";
			this.Size = new Size(6,6);
			myField = Field;
			this.Location = startPoint;
			this.incX = Xinc * 2;
			this.incY = Yinc * 2;
			shapeArray = new Point[4];
			shapeArray[0] = new Point(3,0);
			shapeArray[1] = new Point(6,3);
			shapeArray[2] = new Point(3,6);
			shapeArray[3] = new Point(0,3);
			myColor = Color.Red;
			playMySound(createSound);
			//myField.spawnParticles(2,this.Location);
			

			//myField.Controls.Add(this);
		}

		public Missile(Point startPoint, PlayingField Field, Player owner):base(Field)
		{

			myOwner = owner;
			StartPoint = startPoint;
			myField = Field;
			this.Location = startPoint;
		
		}

		

		public override void  make_move()
		{
			
			base.make_move();
			int x = Location.X - StartPoint.X;
			int y = Location.Y - StartPoint.Y;
			this.distanceMoved = (x*x) + (y*y);
			
			if (this.distanceMoved>60000)
				//if (System.Math.Pow((double)this.distanceMoved,(double)0.5) > 250)
			{
				this.beforeDeath(myOwner);
				this.killMe(myOwner);
			}


			
			
		}

		public override void beforeDeath(Player collidedWith)
			// let's create a harmless explosion
		{
			
			myField.addPlayer(new MExplosion(this.Location, myField, myOwner,true));
		}


	}

	public class MExplosion : Missile
	{
		private int animations=0;
		private int maxAnimations=20;
		private Matrix myMatrix = new Matrix();
		private int fader=255;
		
		private bool colorToggle = true;
		
		public MExplosion(Point startPoint,  PlayingField Field, Player owner, bool isHarmless) : base(startPoint, Field, owner)
		{
			createSound ="bigasteroid.wav"; 
			//Field.player.PlaySound(soundPath + this.createSound);
			playMySound(createSound);
			destroysClass = new String[1];
			if (isHarmless)
			{
				destroysClass[0] = " ";
				className = "harmlessMExplosion";
			}
			else
			{
				destroysClass[0] = "Asteroid";
				className = "MExplosion";
			}
			this.Size = new Size(30,30);
			shapeArray = new Point[6];

			shapeArray[0] = new Point(-10,-20);
			shapeArray[1] = new Point(10,-20);
			shapeArray[2] = new Point(20,0);
			shapeArray[3] = new Point(10,20);
			shapeArray[4] = new Point(-10,20);
			shapeArray[5] = new Point(-20,0);
			myMatrix.Reset();
			// scale the matrix down so that we can shrink the shape defined above
			// just cos I want it a bit smaller
			myMatrix.Scale(0.6f,0.6f);
			myMatrix.TransformPoints(shapeArray);
			myMatrix.Reset();
		}


		
		public override void make_move()
		{ /* override this method so that the explosion doesn't go anywhere */ }

		public override void animate()
		{
			
			
			myColor = Color.FromArgb(fader,Color.Yellow);
			animations++;
			fader-=10;

			//this next bit grows a hexagon
			myMatrix.Reset();
			myMatrix.Scale(1.05f,1.05f, MatrixOrder.Append);
			myMatrix.TransformPoints(shapeArray);


			// this bit grows a couple of circles
			int innerCircle = (int)(animations/2+15);
			int outerCircle = innerCircle + 10;

			
			
			//this one is the edge of the circle
			GraphicsPath myCircle = new GraphicsPath();
			myCircle.AddEllipse(this.Location.X-innerCircle,this.Location.Y-innerCircle,innerCircle * 2,innerCircle * 2);
			//Brush b1 = new SolidBrush(Color.FromArgb(fader,Color.Blue));
			Pen p1 = new Pen(Color.FromArgb(fader,Color.Red),4);
			
			//this one is the filled in portion
			GraphicsPath myCircle2 = new GraphicsPath();
			//myCircle2.AddEllipse(this.Location.X-outerCircle,this.Location.Y-outerCircle,outerCircle * 2,outerCircle * 2);
			myCircle2.AddEllipse(this.Location.X-innerCircle,this.Location.Y-innerCircle,innerCircle * 2,innerCircle * 2);
			Brush b2 = new SolidBrush(Color.FromArgb(fader,Color.Gold));
			myColor = Color.FromArgb(fader,Color.Gold);
			//Pen p2 = new Pen(Color.FromArgb(fader,Color.Yellow),2);
			
			animationArray = new Object[2,2];
			animationArray[0,0] = myCircle;
			animationArray[0,1] = p1;
			animationArray[1,0] = myCircle2;
			animationArray[1,1] = b2;
			
			//return ((animations%maxAnimations==0));
			if (animations%maxAnimations==0 | fader<=0)
			{
				this.beforeDeath(myOwner);
				this.killMe(myOwner);
			}
		}

		public override void beforeDeath(Player collidedWith)
		{
			// if we don't override this method, it inherits from missile
			// and thus spawns another explosion
		}
	

	}

	


	public class Ship:Player
	{
		public int rotationAngle = 0;
		public Point shipCenter;
		public Point[]  shipTarget;
		private Point[] origShape;
		public static int myScore = 0;
		public bool[] controllers;
		public int fireDelayCounter = 0;
		public int singleShotCounter = 0;
		public int singleShotFireDelay = 8;
		// fireDelayCounter is incremented every call to make move
		// which is governed by the time - originally set to 40ms = 25 ticks per second
		// therefore fireDelayCounter is incremented 25 times per second
		// so to fire twice in one second, we need a delay of about 12.5
		// but is int so make it 12
		public int fireDelay = 12;
		public bool incSingleShotCounter = false;
		public int invincibleCounter = 0;

		private enum controls {anticlockwise = 0, clockwise = 1, thrust = 2, brake = 3, fire = 4};

		public Ship(Point startPoint, int Xinc, int Yinc,  PlayingField Field):base(Field)
		{
			
			controllers = new Boolean[5]{false,false,false,false,false};

			score = Ship.myScore;
			this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Ship_KeyDown);
			
			// this next point is used to calculate line equations for the missiles
			// that the ship fires.  As the ship rotates, we also rotate this point
			// and this allows us to work out the gradient (the x increase and y increase)
			// for the missiles' movements
			destroysClass = new String[1];
			destroysClass[0] = " ";
			className = "  Ship";// this will be set after 5 seconds 
			// although we only need one extra point to work out gradients for
			// when new missiles are launched, it needs to be in an array
			// in order to use the matrix.rotatePoints methods
			shipTarget = new Point[1];
			shipTarget[0] = new Point(20,0);
			this.Size = new Size(40,40);
			myField = Field;
			this.Location = startPoint;
			this.incX = 0;
			this.incY = 0;
			shapeArray = new Point[4];
			shapeArray[0] = new Point(20,5);
			shapeArray[1] = new Point(40,40);
			shapeArray[2] = new Point(20,25);
			shapeArray[3] = new Point(0,40);

			origShape = new Point[shapeArray.GetLength(0)];
			Array.Copy(shapeArray,origShape,shapeArray.GetLength(0));
			shipCenter = new Point((int)(ClientRectangle.Width / 2), (int)(ClientRectangle.Height/2));
			myColor = Color.DarkCyan;

		}
		public override void beforeDeath(Player collidedWith)
		{
			Ship.myScore = score;
			myField.addPlayer(new MExplosion(this.Location, myField, myOwner,true));
		}


		public override  void setKeys(KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Z)
			{
				controllers[(int)controls.anticlockwise] = true;
				lastKeyPressed = "anticlock";
			}
					
			if (e.KeyCode == Keys.X)
			{
				controllers[(int)controls.clockwise] = true;
				lastKeyPressed = "clock";
			}

					
			if (e.KeyCode == Keys.K)
				controllers[(int)controls.fire] = true;
					
			if (e.KeyCode == Keys.J)
				controllers[(int)controls.thrust] = true;
					
			if (e.KeyCode == Keys.L)
				controllers[(int)controls.brake] = true;
					
					
					
		}

		private void Ship_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
		}

		public override void launchMissile()
		{
			if (fireDelayCounter%fireDelay==0)
			{
				fireDelayCounter = fireDelayCounter%fireDelay;
				//work out the incX and incY for the new missile
				int incX = shipTarget[0].X - shapeArray[0].X;
				int incY = shipTarget[0].Y - shapeArray[0].Y;
			
				int createX = shapeArray[0].X + Location.X;
				int createY = shapeArray[0].Y + Location.Y;
				Point createAt = new Point(createX,createY);
				// create the missile and tell the playing field of its existence
				myField.addPlayer(new Missile(createAt,incX,incY,myField, this));
				//				myField.addPlayer(new Missile(createAt,incX-1,incY-1,myField, this));
				//				myField.addPlayer(new Missile(createAt,incX+1,incY+1,myField, this));
			}
			
		}
	
		
		
		public override void make_move()
		{
			
			//ship should be invincible for about 5 seconds after being created
			if (this.invincibleCounter<=5000)
			{
				invincibleCounter +=this.myField.Timer.Interval;
				this.myColor = Color.FromArgb(125,Color.White);
			}
			if (invincibleCounter >= 5000)
			{
				this.myColor = Color.DarkGoldenrod;
				this.className = "Ship";
			}
			
			fireDelayCounter++;
			
			if (incSingleShotCounter)
				singleShotCounter++;

			// turn off the counter when the delay has expired
			if (singleShotCounter%singleShotFireDelay==0)
			{
				incSingleShotCounter = false;
				singleShotCounter = 0;
			}

			base.make_move();
			//			if (this.incX<=-1)
			//				this.incX++;
			//			if (this.incX>=1)
			//				this.incX--;
			//			if (this.incY>=1)
			//				this.incY--;
			//			if (this.incY<=-1)
			//				this.incY++;
			if (controllers[(int)controls.anticlockwise] & controllers[(int)controls.clockwise])
			{
				// we need to work out which key gets precedence
				// we will use the lastKeyPressed property
				if (this.lastKeyPressed=="anticlock")
					rotationAngle -=5;
				else
					rotationAngle +=5;
			}
			else
			{

				if (controllers[(int)controls.anticlockwise])
					rotationAngle -=5;
			
				if (controllers[(int)controls.clockwise])
					rotationAngle +=5;
			}

			if (controllers[(int)controls.fire])
				launchMissile(); // don't override the delay - only override the delay for a keypress event (as opposed to keydown)
			
			if (controllers[(int)controls.thrust])
			{
				//work out the gradient and change the xinc and yinc accordingly
				this.incX = shipTarget[0].X - shapeArray[0].X;
				this.incY = shipTarget[0].Y - shapeArray[0].Y;
			}
			if (controllers[(int)controls.brake])
			{
				this.incX = 0;
				this.incY = 0;
			}
			
			
			Matrix myMatrix = new Matrix();
			myMatrix.RotateAt(rotationAngle, shipCenter, MatrixOrder.Append);
			Array.Copy(origShape,shapeArray,shapeArray.GetLength(0));				
			myMatrix.TransformPoints(shapeArray);
			shipTarget[0] = new Point(20,0); 
			myMatrix.TransformPoints(shipTarget);
			

		}

		public override void singleShot()
		{
			// when a shot is fired, reset a counter, and do not allow another shot
			// until a certain time has elasped
			if (singleShotCounter%fireDelay==0)
			{
				singleShotCounter = 0; //reset the counter
				incSingleShotCounter = true;
				//work out the incX and incY for the new missile
				int incX = shipTarget[0].X - shapeArray[0].X;
				int incY = shipTarget[0].Y - shapeArray[0].Y;
			
				int createX = shapeArray[0].X + Location.X;
				int createY = shapeArray[0].Y + Location.Y;
				Point createAt = new Point(createX,createY);
				// create the missile and tell the playing field of its existence
				myField.addPlayer(new Missile(createAt,incX,incY,myField, this));
				//				myField.addPlayer(new Missile(createAt,incX-1,incY-1,myField, this));
				//				myField.addPlayer(new Missile(createAt,incX+1,incY+1,myField, this));
				controllers[(int)controls.fire] = false;
			}

		}
		public override void releaseKeys(KeyEventArgs e)
		{
			switch (e.KeyCode)
			{
				case (Keys.Z):
					controllers[(int)controls.anticlockwise] = false;
					if (lastKeyPressed == "anticlock")
						lastKeyPressed = "";
					break;
				case (Keys.X):
					controllers[(int)controls.clockwise] = false;
					if (lastKeyPressed == "clock")
						lastKeyPressed = "";
					break;
				case (Keys.K):
					controllers[(int)controls.fire] = false;
					break;
				case (Keys.J):
					controllers[(int)controls.thrust] = false;
					break;
				case (Keys.L):
					controllers[(int)controls.brake] = false;
					break;
			}
		}
	}




	public class PlayingField : UserControl
	{
		public Player[] playerArray;
		public Player theShip;
		public Random randomGenerator;
		public SoundPlayer[] soundPlayers = new SoundPlayer[6];		
		public System.Windows.Forms.Timer Timer;
		public int asteroidsRemaining = 0;
		public int playerLivesRemaining = 2;
		private int numOfAsteroidsForNewScreen = 0;
		private bool isGameOver = false;
		public bool bounce, suicide;
		public bool optimiseCollisionDetection = true;

		//private bool shouldCheckCollision = true;
	
		
		public PlayingField(System.Windows.Forms.Timer theTimer, Point myLocation, Size mySize)
		{
			
			
			this.Location = myLocation;
			this.Size = mySize;
			
			
			
			// create an array of sound channels 
			for (int i = 0; i<=soundPlayers.GetLength(0)-1; i++)
				soundPlayers[i] = new SoundPlayer();

			
			// add the passed in timer so that other objects can see it
			Timer = theTimer;
			// now, rather than put some code in the tick event of the timer,
			// we will register this playingfield as a listener (or subscriber) 
			// for the clock's tick event.  We will tell it call this game_Tick event
			// when it ticks.
			Timer.Tick += new System.EventHandler(this.game_Tick);

			
			// play around with the rendering settings to try and get better performance
			this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
			//	this.SetStyle(ControlStyles.DoubleBuffer, true); - this line is actually quicker than the one preceding it, but it is not as smooth
			
			
			
			//this array stores references to all the items on the playing field - except the score
			playerArray = new Player[5];
			
			
			//this random generator is used by various classes mainly for positioning of an instance on the screen
			randomGenerator = new Random();

			this.startGame();
			
		}


		public void startGame()
		{
			for (int i=0; i<=playerArray.GetLength(0)-1; i++)
			{
				if (playerArray[i]!=null)
					playerArray[i].killMe(); // just pass 'this' in - it doesn't matter in this case what it is
				playerArray[i] = null;
			}
			Ship.myScore = 0;
			this.asteroidsRemaining = 0;
			this.numOfAsteroidsForNewScreen = 0;
			this.playerLivesRemaining = 3;
			this.makeShip();
			this.makeAsteroids();
			this.isGameOver = false;
			Timer.Enabled = true;
		}




		public void makeShip()
		{
			Point startPoint = new Point((int)(this.Width/2)-20,(int)(this.Height/2)-20);
			this.theShip = new Ship(startPoint,0,0, this);
			this.addPlayer(this.theShip);
		}

		
		
		
		private void game_Tick(object sender, System.EventArgs e)
		{
			//			for (int z=1; z<=3;z++)
			//				this.spawnParticles(1,new Point((int)(this.Width/2)-20,(int)(this.Height/2)-20));
			//			
			this.Refresh();
			if (this.playerLivesRemaining == 0 & (!this.isGameOver))
			{
				this.gameOver();
			}
			else
			{
				if (!this.isGameOver)
					this.check_collision();
				else
					this.startGame();
			}
		}
	

		public void spawnParticles(int numOfParticles, Point myLocation)
		{
			for (int j=1;j<=numOfParticles;j++)
			{
				//Point jkl = new Point((int)this.Width/2, (int)this.Height/2);

				this.addPlayer(new particle(myLocation,this));
			}
		}

		
		
		
		public void makeAsteroids()
		{
			
			

			numOfAsteroidsForNewScreen++;
			
			// randomly enter pinball / dodgem mode
			if (this.randomGenerator.Next(0,9) == 1)
			{
				this.bounce = true;
			}
			else
			{
				this.bounce = false;
			}

			if (this.randomGenerator.Next(0,9) == 1)
			{
				this.suicide = true;
			}
			else
			{
				this.suicide = false;
			}
			
			int x, y, incX, incY;
			Point startPoint;

			for (int i=1; i<=numOfAsteroidsForNewScreen; i++)
			{

				//get our random start points
				x = (int)(this.randomGenerator.NextDouble() * this.Width);
				y = (int)(this.randomGenerator.NextDouble() * this.Height);

				// if the start points are within a square that bounds the center of the screen
				// where the ship is supposed to be
				// better still, don't go against the centre, go against where the ship is at
				// this time
				int middleX, middleY;
				//just to be safe lets check the ship exists
				if (this.theShip !=null)
				{
					middleX = theShip.Location.X;
					middleY = theShip.Location.Y;
				}
				else
				{
					middleX = (int)this.Width/2;
					middleY = (int)this.Height/2;
				}

				if ( ((x > middleX - 400) & (x < middleX + 400)) & ((y > middleY-400) & (y < middleY + 400)) )
				{
					x = x - 400;
					y = y - 400;
				}

				if (x<=0)
					x = 1;
				if (x>=this.Width)
					x = this.Width-100;

				if (y<=0)
					y = 1;

				if (y>=this.Height)
					y = this.Height - 100;


				
				// get our ramdom directions
				incX = (int)(1 + this.randomGenerator.NextDouble() * 4);
				incY = (int)(1 + this.randomGenerator.NextDouble() * 4);
			
				// make sure we have some that go right to left and bottom to top
				if (this.randomGenerator.NextDouble() > 0.5)
					incX = incX * -1;
				if (this.randomGenerator.NextDouble() > 0.5)
					incY = incY * -1;

				startPoint = new Point(x,y);

				this.addPlayer(new Asteroid(startPoint,incX, incY, this, 3));
			}
			PlaySound("d:\\My Documents\\Visual Studio Projects\\asteroids\\Asteroids\\acid bass drum.wav");
		}

		public virtual void PlaySound(string filename)
		{
			for (int i=0; i<=soundPlayers.GetLength(0)-1;i++)
				if (soundPlayers[i].isReady)
				{
					// we could reach each file into an array of bytes
					// using filestream object.  Then each time that file is requested
					// we could squirt out a new file from the array
					// and thus effectively copying the original file.
					// This may work out quicker than the file.copy method
					// as this way the source file for the sound is only read
					// once.
					
					FileStream myFileStream = new FileStream(filename,  FileMode.Open, FileAccess.Read, FileShare.Read);
					string myTempFile = "d:\\temp\\mysound" + i.ToString() + ".wav";
					
					if (File.Exists(myTempFile))
						File.Delete(myTempFile);
					
					File.Copy(filename,myTempFile);
					soundPlayers[i].PlaySound(myTempFile);
					//soundPlayers[i].Player.FileName = filename;

					//					ThreadStart myStart = new ThreadStart(soundPlayers[i].PlaySound);
					//					Thread myThread = new Thread(myStart);
					//					myThread.Start();

					break;
				}
			

		}

		public void addPlayer(Player newPlayer)
		{
			// we need to redimension the playerArray
			// to do this, we need to clone the playerArray
			// and then redefine it to be one element bigger
			// and then copy the old elements back, and add the new.
			// If anyone knows a simpler way of redimensioning an array, please let me know jason.king@profox.co.uk
			// To be efficient, we could reuse any null elements we find
			
			int length = playerArray.GetLength(0);
			bool shouldAdd = true; 

			if (newPlayer.className=="Asteroid")
			{
				this.asteroidsRemaining++;
			}
			//				if (newPlayer.className=="Ship")
			//				{
			//					this.playerLivesRemaining--;
			//				}

			
			for (int i = 0; i<=length-1; i++)
			{
				

				if (playerArray[i]==null)
				{
					playerArray[i] = newPlayer;
					playerArray[i].MyIndexInOwnerArray = i;
					// now register this playing field as a listener (subscriber) to
					// the new player's OnDeath event
					playerArray[i].OnDeath += new Player.DeathHandler(this.player_Dies);

					//we don't need to add a new element
					shouldAdd = false;
					break; //escape out of loop as there may be more than one
					// null and we don't want to add the player more than once
				}
			}
			if (shouldAdd)
			{
				//create a clone of the original - we could use clone or copyto
				Player[] temp = new Player[length];
				playerArray.CopyTo(temp,0);
				playerArray = new Player[length+1];
				temp.CopyTo(playerArray,0);
				playerArray[length] = newPlayer;
				playerArray[length].MyIndexInOwnerArray = length;
				playerArray[length].OnDeath += new Player.DeathHandler(this.player_Dies);
			}

		}
		private void gameOver()
		{
			this.Timer.Enabled = false;
			// do some score table stuff here.
			MessageBox.Show("Your score is " + Ship.myScore.ToString());
			this.isGameOver = true;
			//			for (int i=0; i<=playerArray.GetLength(0)-1; i++)
			//			{
			//				playerArray[i] = null;
			//			}
			this.Timer.Enabled = true;
			
		}
		public void player_Dies(Player source, System.EventArgs e)
		{
			int theIndex = source.MyIndexInOwnerArray;
			this.playerArray[theIndex]=null;

			switch (source.className)
			{
				case ("Ship"):
					this.playerLivesRemaining--; //this is done when a ship is added to the screen
					this.theShip=null;
					
					//					if (this.playerLivesRemaining < 0)
					//						this.gameOver();
					//					else
					//					{
					//						Thread.Sleep(500);
					//						this.makeShip();
					//					}
					if (this.playerLivesRemaining > 0)
					{
						
						this.makeShip();
					}
					break;
				
				case ("Asteroid"):
					this.asteroidsRemaining--;
					if (this.asteroidsRemaining <= 0)
						this.makeAsteroids();
					break;

			}

		
		}
		public void setPlayers(Player[] thePlayers)
		{
			playerArray = new Player[thePlayers.GetLength(0)];
			Array.Copy(thePlayers,playerArray,thePlayers.GetLength(0));
		}

		
		
		
		public void check_collision()
		{
			for (int i=0; i<=playerArray.GetLength(0)-1; i++)
			{
				bool killI = false;
				/* step through each player
				 * and check that its coordinates against each other player.
				 * If they intersect, remove one, two or none of the players
				 * depending on their destroysClass listing
				 */
				if ((playerArray[i]!=null))
				{
					Rectangle iRec = new Rectangle(playerArray[i].Location,playerArray[i].Size);
					
					for (int j=0; j<=playerArray.GetLength(0)-1; j++)
					{
						if ((i==j) | (playerArray[j]==null))
							continue;  // ignore the rest of the code and loop round - no point checking an object against itself
						 
						// check to see if each is a valid target for the other
						Rectangle jRec = new Rectangle(playerArray[j].Location,playerArray[j].Size);
						bool killJ = false;
						bool canKillJ = isValidTarget(playerArray[i].destroysClass,playerArray[j].className);
						bool canKillI = isValidTarget(playerArray[j].destroysClass,playerArray[i].className);
						
						// if neither are valid targets, loop round, otherwise, check to see if they collide

						if (canKillJ | canKillI)
						{
							
							
							Rectangle ijRec = Rectangle.Intersect(iRec,jRec);
							if (!ijRec.IsEmpty | !this.optimiseCollisionDetection)
							{
							
							#region Check objects intersect by checking points against graphics paths
								if (playerArray[j]!=null)
								{
									Point pointToCheck; 
									foreach(Point p in playerArray[j].shapeArray)
									{
										// convert p into screen coordinates
										int pX = p.X + playerArray[j].Location.X;
										int pY = p.Y + playerArray[j].Location.Y;

										// note - using PointToScreen was not working as expected
										pointToCheck = new Point(pX,pY);
								
										// we need the null check here since any asteroids we have added
										// may not have been drawn yet and hence will not have their regions set up yet
										if (playerArray[i].myPath!=null)
										{
											if(playerArray[i].myPath.IsVisible(pointToCheck))
											{
												killI = canKillI;
												killJ = canKillJ;
												// now we need to check which of the two
												// are destroyed (it may be just one, both or neither)
					
										#region Check if classname appears in target list
												/*
												 foreach(string target in playerArray[i].destroysClass)
												{
													if (playerArray[j].className==target)
														// playerArray[j] is killed
													{
														killJ = true;
														break;
													}

												}
												foreach(string target in playerArray[j].destroysClass)
												{
													if (playerArray[i].className==target)
														// playerArray[i] is killed
													{
														killI = true;
														break;
													}
												}
												*/
										#endregion
												break;
											}
										}
									}
								}
						#endregion

							}
						}
						else
							continue;

						if (killJ)
							playerArray[j].beforeDeath(playerArray[i]);
					
						if (killI)
							playerArray[i].beforeDeath(playerArray[j]);
						
						if (killJ)
							playerArray[j].killMe(playerArray[i]);
						
						if (killI)
						{
							playerArray[i].killMe(playerArray[j]);
							break;
						}
					}
						
				
				}
				
			}
			
		}

		public bool isValidTarget(string[] targetList, string searchFor)
		{
			bool retval = false;
			foreach(string target in targetList)
			{
				if (searchFor==target)
				{
					retval = true;
					break;
				}
			}
			return retval;
		}
		
		protected override void OnPaint(PaintEventArgs pe)
		{
			SolidBrush brush = new SolidBrush(Color.FromArgb(128,Color.Aquamarine));
			int theScore = 0;
			if (this.theShip!=null)
			{
				theScore = this.theShip.score ;
				Font myFont = new Font("Arial",14, FontStyle.Bold | FontStyle.Italic);
				StringFormat drawFormat = new StringFormat();
				drawFormat.FormatFlags = StringFormatFlags.DirectionRightToLeft;
				Point myPoint = new Point(this.Width-10,10);
				pe.Graphics.DrawString( this.playerLivesRemaining.ToString()+ " - " + theScore.ToString(),myFont,brush,myPoint,drawFormat);
			}
			
			for (int i=0; i<=playerArray.GetLength(0)-1; i++)
			{
			
				// it is likely that there are elements in the player array that are null (destroyed asteroids etc)
				// in which case loop around and move on to the next element
				if (playerArray[i]==null)
					continue;


				if (playerArray[i].animationArray!=null)
				{
					// step through an animation array and use its paths and shapes to draw to the screen
					for (int k=0; k<=playerArray[i].animationArray.GetLength(0) - 1; k++)
					{
						if ((playerArray[i].animationArray[k,1] is Brush))
							pe.Graphics.FillPath((Brush)playerArray[i].animationArray[k,1],(GraphicsPath)playerArray[i].animationArray[k,0]);
						else
							pe.Graphics.DrawPath((Pen)playerArray[i].animationArray[k,1], (GraphicsPath)playerArray[i].animationArray[k,0]);
					}
				}
			}
		}


	}



	public class SoundPlayer : UserControl
	{
		private System.ComponentModel.IContainer components;
		//public AxMCI.AxMMControl Player; - beta2 code
		public AxMediaPlayer.AxMediaPlayer Player; // released version code
		public bool isReady = true;
				
		
		public SoundPlayer()
		{
			InitializeComponent();
		}

		
		private void InitializeComponent()
		{
			
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
			
			//this.Player = new AxMCI.AxMMControl(); // beta2 code
			this.Player = new AxMediaPlayer.AxMediaPlayer();
			// This next line is either casting the activeX control to some handy type
			// or perhaps glueing an interface to it.  Maybe.  I don't know.  Too highbrow for me.  Can anyone explain?
			
			((System.ComponentModel.ISupportInitialize)(this.Player)).BeginInit();
			this.Player.Enabled = true;
			this.Player.Name = "Player";
			this.Player.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("Player.OcxState")));
			this.Player.TabIndex = 0;
			this.Player.Visible = false;
			//this.Player.Done += new AxMCI.DmciEvents_DoneEventHandler(this.Player_Done); beta2 code
			this.Player.PlayStateChange += new AxMediaPlayer._MediaPlayerEvents_PlayStateChangeEventHandler(Player_Done);
			
			this.Controls.AddRange(new System.Windows.Forms.Control[] {this.Player});
			((System.ComponentModel.ISupportInitialize)(this.Player)).EndInit();
			this.Player.AutoStart = true; // release version code
			
			/* beta2 code
			this.Player.DeviceType = "WaveAudio";
			this.Player.Wait = true;
			this.Player.Shareable = false;
			*/
			
			this.Player.SendPlayStateChangeEvents = true; // release code version 
			//this.Player.Notify = true; // beta2 code
			
			
			
		}
		// private void Player_Done(object sender, AxMCI.DmciEvents_DoneEvent e) - beta2 code
		private void Player_Done(object sender, AxMediaPlayer._MediaPlayerEvents_PlayStateChangeEvent e)
		{
			
			#region Released version of C#
			if	( ((AxMediaPlayer.AxMediaPlayer)(sender)).PlayState == MediaPlayer.MPPlayStateConstants.mpStopped)
			{
				
				// in order for the File.Delete to work, we need to force the player to release the file
				// Without documentation to help, I am forced to make it error with an empty filename
				// Need to store the old filename before setting the new one to ""
				string filename = this.Player.FileName;
				this.Player.Open("");
				File.Delete(filename);
				this.isReady = true;
				
			}
			#endregion

			#region beta2 code
			//this.Player.Command = "Close"; beta2 code
			
			//File.Delete(this.Player.FileName); //beta2 code
			//	this.Player.FileName = ""; // beta2 code
			/*
						if (e.notifyCode==1)
							this.isReady = true;
						else
							this.isReady = false
			*/
			#endregion
		}

		
		
		public void PlaySound(string fileName)
		{
			
			if (this.isReady)
			{
				this.isReady = false;
			
				/* beta2 code
				if (fileName!=this.Player.FileName)
					this.Player.FileName = fileName;
			 			
				this.Player.Command = "Close";
				this.Player.Command = "Open";
				this.Player.Command = "Play";
				*/
				// release code version
			
				this.Player.Open(fileName);
				
			
			}
			
		}
		

		public void killPlayer()
		{
			
			//this.Player.Command = "Close"; //beta code version
			this.Dispose(true);
		}
		
			

	}
	
	public class SoundThread
	{
		public string soundFile;
		public PlayBlah soundFlags;
		
		public SoundThread(string fileName)//, PlayBlah flags)
		{
			this.soundFile = fileName;
			this.soundFlags = PlayBlah.Filename|PlayBlah.Asynchronously;
		}
		public enum PlayBlah 
		{ 
			Synchronously = 0x0000, 
			Asynchronously = 0x0001, 
			NoDefault = 0x0002, 
			Memory = 0x0004, 
			Loop = 0x0008, 
			NoStop = 0x0010, 
			NoWait = 0x00002000, 
			Alias = 0x00010000, 
			AliasId = 0x00110000, 
			Filename = 0x00020000, 
			Resource = 0x00040004, 
			Purge = 0x0040, 
			Application = 0x0080 
		} 

		//		[DllImport("winmm.dll")]
		//		public static extern int PlaySound(String pszSound, int hmod,PlayBlah fdwSound);

		public void Play()
		{
			
			//	PlaySound(this.soundFile,0,this.soundFlags);
		}

	}


}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
Profox Jase
Co-Author, "Cross-Platform .NET Development: Using Mono, Portable.NET, and Microsoft .NET"
(Apress, 2004, ISBN: 1-59059-330-8)
The Book

Comments and Discussions