// Workshop 8 part 1

import sdljava.*;
import sdljava.video.*;
import sdljava.event.*;
import sdljava.ttf.*;
import sdljava.mixer.*;
import java.util.LinkedList;
import java.util.ListIterator;

	// This is a general purpose vector class
class c_vector
{

		// Constructor that takes another vector as input
	public c_vector( c_vector value )
	{
		x = value.x;
		y = value.y;
	}

		// Constructor that takes two floats as input
	public c_vector( float a, float b )
	{
		x = a;
		y = b;
	}

		// Constructor that takes one float as input
	public c_vector( float value )
	{
		x = y = value;
	}

		// Constructor that takes no input
	public c_vector()
	{
		x = y = 0.0f;
	}

		// Normalises the vector
	public void normalise()
	{
			// Retrieve the magnitude
		float len = get_length();
		if( len > 0.0f )
		{
			// Normalise the vector by dividing the components by this magnitude
			x /= len;
			y /= len;
		}
		else	// This should stop divide by zero errors
			x = y = 0.0f;
	}

		// Returns the length of the vector
	public float get_length()
	{
			// Return the magnitude (length) using Pythagoras' theorem
		return (float) Math.sqrt( (x*x) + (y*y) );
	}

		// Our vector's components
	public float x, y;
}

class game_object
{
		// Static function for storing the screen size
	public static void set_screen_size(c_vector screenIn)
	{
			// This will be used in the update functions, so see if the object collides with the screen
		screen = screenIn;
	}

		// Safe method for (eventually) adding an object to the main object list (similar in concept to the blacklist flag)
	public static void add_game_object(game_object in)
	{
		// We will be keeping an internal static store of all objects in a temporary list

		// If this list does not exist..
		if( object_list == null )
		{
			// .. create it!
			object_list = new LinkedList<game_object>();
		}
			// Add the object to the list
		object_list.add(in);
	}

	public static LinkedList<game_object> get_game_object_list()
	{
		// We need to do two things here: return our list, and set the variable to null

			// To do this, we declare a temporary variable to hold the list
		LinkedList<game_object> temp = object_list;
			// Then set the object list to null so that we can create a new (empty) one next time we need to add something
		object_list = null;
			// And finally, return the actual list
		return temp;
	}

	public game_object()
	{
		position = new c_vector();
		size = new c_vector();
		direction = new c_vector();
		speed = 0;
		image = null;
		blacklist = false;
	}

		// Adds the object to the blacklist (i.e. flags that it should be removed)
	public void blacklist_add()
	{
		blacklist = true;
	}

		// Queries whether the object is on the blacklist
	public boolean blacklist_get()
	{
		return blacklist;
	}

		// For setting the movement direction of the object
	public void set_direction(c_vector in)
	{
			// The direction vector is a normalised unit vector
			// We don't know what the vector we've been given is, so we will normalise it
		in.normalise();
		direction = in;
	}

	public boolean update(float deltaT_s)
	{
			// Update the position
		position.x +=  deltaT_s * direction.x * speed;
		position.y +=  deltaT_s * direction.y * speed;

			// Test against the sides of the screen, keeping track of whether it hits
		boolean hits_sides = false;
		if( position.x - (size.x/2) < 0.0f )
		{
			position.x = size.x/2;
			hits_sides = true;
		}
		else if( position.x + (size.x/2) > screen.x )
		{
			position.x = screen.x - (size.x/2);
			hits_sides = true;
		}

		if( position.y - (size.y/2) < 0.0f )
		{
			position.y = size.y/2;
			hits_sides = true;
		}
		else if( position.y + (size.y/2) > screen.y )
		{
			position.y = screen.y - (size.y/2);
			hits_sides = true;
		}

			// Return whether the object hits the sides of the screen
		return hits_sides;
	}

	public void draw(SDLSurface screenIn) throws SDLException
	{
			// Draw the object
		SDLRect rectangle = new SDLRect((int)position.x-(int)(size.x/2.0f),(int)position.y-(int)(size.y/2.0f),(int)size.x,(int)size.y);
		image.blitSurface(screenIn,rectangle);
	}

		// Performs a basic collision test, returning true if the objects collide
	protected static boolean collide(game_object a, game_object b)
	{
		// This static function performs a basic collision test
		// It does not decide what to do when two objects collide, as this requires knowledge of the object types

		if( a.position.x - (a.size.x/2) < b.position.x + (b.size.x/2)   &&   a.position.x + (a.size.x/2) > b.position.x - (b.size.x/2) )
		{
			// If these tests pass, it means that the objects are at least partially vertically aligned
			// We now need to see if they are also horizontally aligned.
			// If it is, we will have a collision

			if( a.position.y - (a.size.y/2) < b.position.y + (b.size.y/2)   &&   a.position.y + (a.size.y/2) > b.position.y - (b.size.y/2) )
			{
				// If these final tests pass, it means that the objects are also horizontally aligned
				// I.e. they intersect (we have a collision)
				return true;
			}
		}
		return false;
	}

		// Performs and resolves a collision test
	public void collision_test(game_object in)
	{
		// The base game_object class does nothing - this function must be overridden by child objects to do something sensible
	}

	protected c_vector position;
	protected c_vector size;
	protected c_vector direction;
	protected float speed;
	protected SDLSurface image;
	protected static c_vector screen;
	protected boolean blacklist;
	protected static LinkedList<game_object> object_list;
}

class bullet extends game_object
{
		// Bullet constructor
		// Java note: the no-arg constructor of the super class will be automatically called before this one.
	public bullet( game_object originIn, SDLSurface imageIn, c_vector directionIn, c_vector start_pos, float speedIn )
	{
		image = imageIn;
		size.x = image.getWidth();
		size.y = image.getHeight();
		direction = directionIn;
		position = start_pos;
		speed = speedIn;
		origin = originIn;
	}

		// The bullet's update function
	public boolean update(float deltaT_s)
	{
		// For a bullet, we need to do something very slightly different for the update

		// Perform the regular update, making a note of whether we hit the sides of the screen
		boolean hits_sides = super.update(deltaT_s);

			// If we do hit the sides, we will be going off the screen, so need to be flagged for removal:
		if( hits_sides )
			blacklist_add();

			// Still return whether we hit the sides, just for completeness ;)
		return hits_sides;
	}

		// For retrieving the origin object
	public game_object get_origin()
	{
		return origin;
	}

		// Performs and resolves a collision test
	public void collision_test(game_object in)
	{
			// We won't bother doing anything ourselves, but will refer the test over to the other object:
		if( !(in instanceof bullet) )
		{		// Provided the other objet isn't another bullet, let it perform the collision test:
			in.collision_test(this);
		}
	}
		// The game object that fired the bullet
		// This will be useful when we check for collisions, as we won't test against the object that fired it
	protected game_object origin;
}

class spaceship extends game_object
{
		// Space ship constructor
		// Java note: the no-arg constructor of the super class will be automatically called before this one.
	public spaceship(SDLSurface imageIn, c_vector start_pos, float speedIn, c_vector shoot_directionIn, SDLSurface bullet_imageIn, float bullet_speedIn)
	{
		image = imageIn;
			// Determine our size from the image we have been given
		size.x = image.getWidth();
		size.y = image.getHeight();
		position = start_pos;
		shoot_direction = shoot_directionIn;
		bullet_image = bullet_imageIn;
		bullet_speed = bullet_speedIn;
		speed = speedIn;
		kills = 0;
	}

		// This function is called whenever we want the space ship to fire a bullet
	public bullet fire()
	{
			// Create and return a new bullet
		return new bullet((game_object)this,bullet_image,shoot_direction,new c_vector(position), bullet_speed );
	}

		// Performs and resolves a collision test
	public void collision_test(game_object in)
	{
			// Call the collision test function
		if( collide(this,in) )
		{
			// A collision has taken place
			// What we do now depends on what type the other object is:
			if( in instanceof bullet )
			{
				// We have collided with a bullet (i.e. we've been shot at!!)
					// Check that it wasn't our bullet
				if( ((bullet)in).get_origin() != this )
				{
						// We will create a little explosion, just as a special effect ;)
						// This is a game_object, as it needs to be updated and drawn,
						// so we add it to the main list using our safe add_game_object function:
					add_game_object((game_object)new ss_explosion(new c_vector(in.position),0.3f));
						// The bullet is no longer required, as it has found its mark
					in.blacklist_add();

						// This is where we will adjust our health, and possibly get destroyed in a nice big explosion....
				}
			}
		}
	}

		// Notifies the ship that it has killed something
	public void add_kill()
	{
		kills++;
	}

		// Retrieves the number of kills
	public int get_kills()
	{
		return kills;
	}

		// The direction that new bullets will fire in
	protected c_vector shoot_direction;

		// The image to use for new bullets
	protected SDLSurface bullet_image;

		// The speed of a new bullet:
	protected float bullet_speed;

		// The number of kills that the space ship has made
	protected int kills;
}

class enemy extends spaceship
{

	public enemy(SDLSurface imageIn, c_vector start_pos, float speedIn, c_vector shoot_directionIn, SDLSurface bullet_imageIn, float bullet_speedIn, c_vector move_direction, float shoot_timeIn, int healthIn)
	{
			// Call the spaceship's constructor
		super(imageIn, start_pos, speedIn, shoot_directionIn, bullet_imageIn, bullet_speedIn);

			// Set ourselves moving in the given direction
		set_direction(move_direction);
			// The timer will be used for how often we can shoot
		timer = 0.0f;
			// The time in seconds between shots
		shoot_time = shoot_timeIn;
			// How many hits until we get destroyed
		health = healthIn;
	}

	public boolean update(float deltaT_s)
	{
			// Update the timer for how often we shoot
		timer += deltaT_s;

			// If the amount of time that has passed (as stored in our timer variable) is greater than our shoot time,
			// it is time to shoot something!
		if( timer >= shoot_time )
		{
				// The add_game_object function provides a means of safely adding a new game object to the main list
			add_game_object((game_object)fire());

				// We will also reset the timer
			timer = 0.0f;
		}

			// Again, see if we have hit the sides of the screen
		boolean hits_sides = super.update(deltaT_s);

			// If we have hit the sides, we will assume that we have passed off the edge of the screen, and are no longer in game play
			// So, set our blacklist flag
		if( hits_sides )
			blacklist_add();

		return hits_sides;
	}

		// Performs and resolves a collision test
	public void collision_test(game_object in)
	{
			// Call the collision test function
		if( collide(this,in) )
		{
			// A collision has taken place
			// What we do now depends on what type the other object is:
			if( in instanceof bullet )
			{
				// We have collided with a bullet (i.e. we've been shot at!!)
					// Check that it wasn't our bullet
				if( ((bullet)in).get_origin() != this )
				{
						// We will create a little explosion, just as a special effect ;)
						// This is a game_object, as it needs to be updated and drawn,
						// so we add it to the main list using our safe add_game_object function:
					add_game_object((game_object)new ss_explosion(new c_vector(in.position),0.3f));
						// The bullet is no longer required, as it has found its mark
					in.blacklist_add();
						// We are now injured
					health -= 1;
						// If our health is zero, we have been destroyed
					if( health <= 0 )
					{
							// This would be a good place to add a big explosion ;)

							// Set our blacklist flag, so that we can be removed at a convenient time
						blacklist_add();

							// If the bullet originated from a spaceship...
						if( ((bullet)in).get_origin() instanceof spaceship )
						{
								// ... we will add to that ship's list of kills
							((spaceship)((bullet)in).get_origin()).add_kill();
						}
					}

				}
			}
		}
	}

		// Counter used for timing the shooting rate
	float timer;
		// The 'recharge time' - i.e. the time between shots
	float shoot_time;
		// How many hits until we get destroyed - this will be moved to the spaceship class
	int health;
}

	// A single sprite explosion
class ss_explosion extends game_object
{
		// A static init function for saving the image to use
	public static void init(SDLSurface imageIn, MixChunk soundIn)
	{
		explosion_image = imageIn;

		explosion_sound = soundIn;
	}

	public ss_explosion(c_vector positionIn, float durationIn)
	{
		position = positionIn;
		duration = durationIn;
		image = explosion_image;
		size.x = image.getWidth();
		size.y = image.getHeight();

		try
		{
			// Try to play the sound
			// parameters are: channel to play on (-1 = first available)
			//                 the sound to play
			//                 number of repeats
			SDLMixer.playChannel(-1,explosion_sound,0);
		}
		catch( SDLException e )
		{
			// If there are loads of sounds being played, it won't be able to play this one too
		}
	}

		// Overridden update function
	public boolean update(float deltaT_s)
	{
		// There isn't much to update for one of these

		// Count down our duration
		duration -= deltaT_s;

		// If our duration has reached zero, remove ourselves
		if( duration <= 0.0f )
			blacklist_add();

			// We're not interested in checking whether it has hit the sides of the screen
		return false;
	}

		// How long the sprite will survive
	protected float duration;
		// The image to use
	protected static SDLSurface explosion_image;
		// The sound to use
	protected static MixChunk explosion_sound;
}

class s08_p01
{
		// Our SDL surface for drawing on
	static SDLSurface screen;

		// The player controllable space ship
	static spaceship my_ship;

		// The direction that the player controllable ship is moving in according to the user input
	static c_vector ship_direction;

		// List that contains all the game objects in our game
	static LinkedList<game_object> game_objects;

		// This will store a font
	static SDLTrueTypeFont main_font;

		// Timer used in enemy spawning
	static float enemy_timer;

		// The image used for enemies
	static SDLSurface enemy_image;

		// The image used for enemy bullets
	static SDLSurface enemy_bullet_image;



		// We will call this function whenever we want to exit the program.
		// It uninitialises SDL and forces a program exit.
	public static void exit(int value)
	{
		SDLMain.quit();
		System.out.println("Exiting..");
		System.exit(value);
	}

		// In this function, we retrieve and handle events
	public static boolean handle_events()
	{
		try
		{
			// SDL stores events in a queue.
			// We can either wait for events, in which case the function we call will not return until there is an event,
			// or we can have a quick look at the event queue, using a function that will retrieve an event if there is one, returning null if there isn't.
			// In an interactive game, it's not much use if we get stuck waiting for events, as we won't be able to draw or update the scene.
			// Therefore, we want to use the 'quick look' option.
			// This is called polling for events.
			// The waiting technique is known as blocking.

				// Poll for events
			SDLEvent event = SDLEvent.pollEvent();

				// If there was an event..
			if( event != null )
					// What we do depends on the type
				switch( event.getType() )
				{
					case SDLEvent.SDL_QUIT:
						// This event type is generated when the user clicks on the 'x' to close the window
						return true;
					case SDLEvent.SDL_KEYDOWN: // The user has pressed a key
						{
								// This means that the event is actually of a sub-type called an SDLKeyboardEvent.
								// If we cast the event to this type, we can retrieve the actual key type
							int key = ((SDLKeyboardEvent) event).getSym();

								// What we do now depends on the key that was pressed
							switch( key )
							{
								case SDLKey.SDLK_ESCAPE:
									exit(0);
								case SDLKey.SDLK_UP:
									ship_direction.y += -1.0f;
									my_ship.set_direction(new c_vector(ship_direction));
									break;
								case SDLKey.SDLK_DOWN:
									ship_direction.y += 1.0f;
									my_ship.set_direction(new c_vector(ship_direction));
									break;
								case SDLKey.SDLK_LEFT:
									ship_direction.x += -1.0f;
									my_ship.set_direction(new c_vector(ship_direction));
									break;
								case SDLKey.SDLK_RIGHT:
									ship_direction.x += 1.0f;
									my_ship.set_direction(new c_vector(ship_direction));
									break;
								case SDLKey.SDLK_SPACE:
										// This will be the fire button
										// We call our space ship's fire function
										// This returns a bullet, which is a game object
										// To get the game object updated, we need to add it to our list
										// Since this list dictates the drawing order too, we will add it to the front of the list
										// Since our ship is at the back, the bullets will be drawn under it.
									game_objects.addFirst((game_object)my_ship.fire());
									break;
								default:
							}
						}
						break;

					case SDLEvent.SDL_KEYUP: // The user has released a key
						{
								// This means that the event is actually of a sub-type called an SDLKeyboardEvent.
								// If we cast the event to this type, we can retrieve the actual key type
							int key = ((SDLKeyboardEvent) event).getSym();

								// What we do now depends on the key that was pressed
							switch( key )
							{
								case SDLKey.SDLK_UP:
									ship_direction.y -= -1.0f;
									my_ship.set_direction(new c_vector(ship_direction));
									break;
								case SDLKey.SDLK_DOWN:
									ship_direction.y -= 1.0f;
									my_ship.set_direction(new c_vector(ship_direction));
									break;
								case SDLKey.SDLK_LEFT:
									ship_direction.x -= -1.0f;
									my_ship.set_direction(new c_vector(ship_direction));
									break;
								case SDLKey.SDLK_RIGHT:
									ship_direction.x -= 1.0f;
									my_ship.set_direction(new c_vector(ship_direction));
									break;
							}
						}
						break;

					default:
				}

		}
		catch(SDLException e)
		{
				System.err.println("Error while polling event : " + SDLMain.getError());
  				exit(1);
		}

		return false;

	}

		// This function will create a new enemy ship
	public static void create_new_enemy()
	{

			// Create our space ship
		enemy new_enemy = new enemy(enemy_image,				// The image to use for the ship
					new c_vector((int)((float)Math.random()*(screen.getWidth()-enemy_image.getWidth())),enemy_image.getHeight()/2),	// The starting position of the ship
					100.0f,						// The speed of the ship
					new c_vector(0,1),				// The direction that bullets are fired at
					enemy_bullet_image,				// The image to use for the bullets
					300.0f,						// The speed of the bullets
					new c_vector(0,1),				// The direction that the enemy will move in
					1.0f,						// The fire rate of the enemy
					3);						// The number of shots that are required to kill the enemy

			// Add the space ship to the main game object list
		game_objects.add((game_object)new_enemy);

	}

		// In this function, we update our scene
	public static void update( float deltaT_s )
	{

			// Update our timer
		enemy_timer += deltaT_s;

			// This will be triggered every second
		if( enemy_timer >= 1.0f )
		{
				// Create a new enemy
			create_new_enemy();
				// Reset our timer
			enemy_timer = 0.0f;
		}


			// Generate an iterator for the first item in the list
			// (Iterators are useful helper classes that allow us to cycle through a list.
			//   We generate one that starts at the beginning of the list,
			//   and we will use it to retrieve the next item)
		ListIterator it = game_objects.listIterator(0);

			// Go through the list
		while( it.hasNext() )
		{
				// Retrieve the next item
			game_object current = (game_object) it.next();

				// Update the object
			current.update(deltaT_s);

			// We now need to perform a collision test using this object against all other objects
			// However, since our objects are in a list, we can eliminate multiple calls by only testing
			// against all other objects further up than the current one in the list.
			// If we didn't do this, we would end up testing each collision twice:
			// consider a list: A, B, C
			// If we take object A, and perform tests going through the list:
			// A vs A (we can easily detect that)
			// A vs B
			// A vs C
			// Okay, fair enough, let's move on to object B:
			// B vs A   whoops, we've already done this! This is the same as A vs B, since the object order doesn't matter
			// Thus, if we start with the next object in the list, we can remove this problem, and the first test for B becomes:
			// B vs C
			// This also has the added bonus that we don't even have to test C!

				// Create a new iterator starting with the next item in the list
			ListIterator collisionIt = game_objects.listIterator(it.nextIndex());

				// Follow this iterator through to the end of the list
			while( collisionIt.hasNext() )
			{
					// Retrieve the next object
				game_object next = (game_object) collisionIt.next();
					// Perform the collision test and resolution
				current.collision_test(next);
			}

				// If an object needs to be deleted, it will set an internal 'blacklist' flag
				// If this flag is set, we need to remove it from our main game objects list.
				// Why might an object need to be deleted?
				// There are various reasons, for example: if the object explodes, or if a bullet reaches the edge of the screen
			if( current.blacklist_get() )
				it.remove();
		}

			// During our update, we may have ended up with extra objects that need to be added to our main object list
			// These were stored in a static list within the game_object class
			// Let's retrieve that list:
		LinkedList<game_object> extra_objects = game_object.get_game_object_list();
			// And if it isn't empty, add all the objects from it into our main game_objects list:
		if( extra_objects != null )
			game_objects.addAll(extra_objects);
			// All the extra objects will now be in the main objects list
	}

		// Draws a HUD
	public static void draw_HUD(SDLSurface screenIn) throws sdljava.SDLException
	{
			// Generate some text that says how many kills the player has made
			// To do this, we use the main font, and use it to generate an RGBA (actually, SDL stores it as ARGB) SDLSurface
			// We can then blit that to the screen as usual
		SDLSurface kills_text = main_font.renderTextBlended("Kills: "+my_ship.get_kills(), new SDLColor(255,255,255) );

			// Rectangle for where we're blitting to
			// For blitting operations the size is not actually used, just the location (the first two values)
		SDLRect rectangle = new SDLRect(10,10,0,0);

			// Blit the kills text to the screen, using the rectangle to specify the location
		kills_text.blitSurface(screenIn,rectangle);

	}

		// In this function, we draw our scene
		// Upon encountering an error, this function throws an SDLException, which is passed on from SDL function calls
	public static void draw() throws sdljava.SDLException
	{
			// First, we clear the screen
		screen.fillRect(screen.mapRGB(0,0,0));

			// Generate an iterator for the first item in the list
		ListIterator it = game_objects.listIterator(0);
			// Go through the list
		while( it.hasNext() )
		{
				// Retrieve the next object in the list
			game_object current = (game_object) it.next();

				// Draw it to the screen
			current.draw(screen);
		}

			// We will draw the HUD now
		draw_HUD(screen);

		screen.flip();
	}


	public static void main(String[] args)
	{

			// Create an SDL object
		SDLMain sdl = new SDLMain();

			// SDL uses exceptions when it encounters problems
		try
		{
				// Initialise SDL to use its video (graphics) and audio capabilities
			sdl.init(SDLMain.SDL_INIT_VIDEO | SDLMain.SDL_INIT_AUDIO);
				// SDL uses what it calls a 'surface' as a window.
			screen = SDLVideo.setVideoMode(640, 480, 0, 0 );

				// Tell the game object class what size screen we're using
			game_object.set_screen_size(new c_vector(640.0f,480.0f));

				// Initialise the TTF (True Type Font) utility
			SDLTTF.init();

				// Load a font for use. We have to specify a pixel height for the font.
				// FreeSans.ttf is a free font available from: http://www.nongnu.org/freefont/
				// It is released under the GNU GPL
			main_font = SDLTTF.openFont("FreeSans.ttf",20);

				// Initialise the audio capabilities
				// Note that SDL must be initialised with SDL_INIT_AUDIO before we call this
				// Parameters: Sampling frequency (44100 is CD quality)
				//             Format (various ones are available)
				//             Output channels 1 = mono, 2 = stereo
				//             Chunksize, the size of a mixed sample - i.e. something internal to SDL that we don't usually have to worry about. Changing this to a lower value on a slow system may make the sound skip, if too large, sounds may lag.
			SDLMixer.openAudio(44100, SDLMixer.AUDIO_S16SYS, 1, 256);
				// Set volume for all channels (signified by the -1) to the maximum of 128
			SDLMixer.volume(-1, 128);


				// Load an image for the small explosion
			SDLSurface small_explosion = SDLVideo.loadBMP("small_explosion.bmp");
				// We will use colour keying for transparency:
				// all we need to do is set the colour that we will use as transparent
				// here, we are just using black:
			small_explosion.setColorKey(SDLVideo.SDL_SRCCOLORKEY,small_explosion.mapRGB(0,0,0));
				// Load a sound
			MixChunk small_explosion_sound = SDLMixer.loadWAV("hit.wav");
				// Call the explosion init, sending the image and our sound
			ss_explosion.init(small_explosion, small_explosion_sound);

				// Again, load an image
			SDLSurface my_ship_image = SDLVideo.loadBMP("my_ship.bmp");
				// Set black as the transparent colour:
			my_ship_image.setColorKey(SDLVideo.SDL_SRCCOLORKEY,my_ship_image.mapRGB(0,0,0));

				// Again, load an image
			SDLSurface my_bullet_image = SDLVideo.loadBMP("my_bullet.bmp");
				// Set black as the transparent colour:
			my_bullet_image.setColorKey(SDLVideo.SDL_SRCCOLORKEY,my_bullet_image.mapRGB(0,0,0));

				// Again, load an image
			enemy_image = SDLVideo.loadBMP("enemy.bmp");
				// Set black as the transparent colour:
			enemy_image.setColorKey(SDLVideo.SDL_SRCCOLORKEY,enemy_image.mapRGB(0,0,0));
				// Again, load an image
			enemy_bullet_image = SDLVideo.loadBMP("enemy_bullet.bmp");
				// Set black as the transparent colour: (you just can't beat good old cut and pasted comments)
			enemy_bullet_image.setColorKey(SDLVideo.SDL_SRCCOLORKEY,enemy_bullet_image.mapRGB(0,0,0));

				// Create our space ship
			my_ship = new spaceship(my_ship_image,				// The image to use for the ship
						new c_vector(320,240),			// The starting position of the ship
						300.0f,					// The speed of the ship
						new c_vector(0,-1),			// The direction that bullets are fired at
						my_bullet_image,			// The image to use for the bullets
						500.0f);				// The speed of the bullets

				// We want some means of storing a dynamic number of space ships.
				// We will need to peform various operations on them, such as updating and drawing them.
				// They will also need to be able to shoot at us, and we want to be able to shoot at them.
				// Thus, we also need a way of storing bullets, and a means of removing them from the game.
				// We will address both these points by considering both a ship and a bullet as a 'game object'.
				// If we then store these game objects in a list, we can cycle through the list to update and draw them.
				// If something gets created, it will be added to the list, and if it gets destroyed, it will be removed from the list.
				//
				// But why not put bullets in a list for each space ship?
				// If we did that, we would have a problem: what if the space ship gets blown up and is deleted?
				// The space ship's bullet list would also be deleted, and its active bullets removed (i.e. bullets that were fired by it, and are still flying through space).
				// We don't want this, so the bullets need to be stored outside the ship.

				// Create our main game object list
			game_objects = new LinkedList<game_object>();

				// Add the space ship to the list
			game_objects.add((game_object)my_ship);

				// We will use this for storing the direction that the user input indicates the ship should move in
			ship_direction = new c_vector();


				// Timing is one of the most crucial aspects of an interactive game-like program.
				// Since the graphics on screen can take a variable amount of time to draw,
				// we cannot rely on a constant frame rate. Besides, if we run our program on a
				// faster or slower machine, it will be different again.
				// We must therefore calculate the amount of time that has elapsed between each 
				// iteration of our game loop, and use this when we update things.
			long previous_time = 0, current_time = 0, deltaT = 0;
			float deltaT_s = 0.0f;

			current_time = System.currentTimeMillis();
			previous_time = current_time;

				// This will store whether or not the user has asked to quit
			boolean quit = false;
	
				// This is our main "game loop", and we will run it 
				// while we've not been asked to quit...
			while( quit == false )
			{
					// When the user presses a key, or uses the mouse, that input is stored in SDL as an 'event'.
					// As an interactive program, we need to look at these events and decide what to do about them.
					// Our function here also returns true if we want to quit:
				quit = handle_events();
	
					// In an interactive program, be it a game or whatever, we usually have a variety of things to update each frame.
					// These could be character animations, physics simulations, explosions, whatever we want...
				update(deltaT_s);
	
					// Finally, we need to draw our scene
				draw();

					// Update our current time
				current_time = System.currentTimeMillis();
					// Work out the frame rate for that frame
				deltaT_s = (float)(current_time-previous_time)/1000.0f;
					// For the next frame, our current time will the the previous one
				previous_time = current_time;

			}

			exit(0);

		}
		catch(SDLException e) // Catch SDL problems
		{
				// We shall handle any problems by printing a stack trace:
			e.printStackTrace();
				// and an explanation if that wasn't enough
			System.err.println("SDL encountered a problem");
			exit(1);
		}

	}
}