Jumpbox.java


import java.awt.*;
import java.util.*;
import java.awt.event.*;

public class Jumpbox extends Canvas implements WindowListener,  
															  MouseMotionListener,
															  Runnable
{
	/** Konstante: Hintergrundfarbe **/
	private static final Color hG = new Color(120,120,120);
	/** Konstante: Namenszug f�rs Fenster **/
	private static final String joeStudent	= "Jumpbox von Xxxx Xxxxxxx 842771";
   /** Konstante: Fensterh�he **/
	private static final int fHoehe 			= 500;
	/** Konstante: Fensterbreite **/
	private static final int fBreite 		= 400;
	/** Konstante: Kantenl�nge der Boxen **/
	private static final int kLaenge       = 50;
	/** Konstante: Mindestabstand zum Spielfeldrand in Pixeln **/
	private static final int mA 				=	1;
	/** Konstante: Standartschriftart f�r die Beschriftung der K�stchen 
	* wenn der Font nicht gefunden wird, wird der Defaultfont des Systems genommen **/
	private static final Font standartSchrift = new Font("Times New Roman",1, 18);
	/** Konstante: Array der acht m�glichen Spielfarben **/
	private static final Color[] farben		= {Color.blue, Color.cyan, Color.green,
													Color.magenta, Color.orange, Color.pink,
													Color.red, Color.yellow};
   /** Array der vier aktuellen Richtungsfarben **/
	private int[] ia ={1,2,3,5};
	/** Ausrichtungsindex des Ziels **/
	private  int aI = 0;
	/** Zaehler, wie oft getroffen wurde bzw. danebengehauen, um den Zeitpunkt
	 * der Neuen Richtungsskala zu bestimmen **/
	private int anzZuege= 0;
	/** Konstante: Array der Richtungsbuchstaben **/
	private static final String[] rb 		= {"L","R","O","U"};

	/** Klassenvariable: der Zufallszahlenlieferrant **/
	private static Random zufall;
	/** Klassenvariable: die Spielzeit, default ist 15 **/
	private static int spielzeit = 15000;
	/** Punktez�hler **/
	private int punkte = 0;
	/** Rechteck das zu treffen ist **/
	private Rectangle ziel = new Rectangle (1,kLaenge,kLaenge,kLaenge);

	/** Malobjekt **/
	private Graphics othermeinG;

	/** Instanz von sich selbst fuer die main- Methode **/
	private static Jumpbox j;

	/** Das Fenster in dem das Spiel stattfinden soll **/
	private static Frame fenster;

	/** Variable die der run-Methoder verr�t, welche Annimation richtig
       ist **/
	private boolean warTreffer = false;
	/** Variable die anzeigt, ob MouseEvents behandelt werden oder nicht **/
	private static boolean beachteMaus = true;

	/** Der Smily **/
	private Image smile;
	/** Der Grummelkopp **/
	private Image grummel;
	
	/** Variable fuer die Startzeit, um mit der Spielzeit zu vergleichen.**/
	private long startzeit;
	
	/** Varoab�e fuer die Zeit des Iconifizierens **/
	private long stopzeit;





/*****************************************************************************/
/** 
*Sollte ein Fenster mit Spielfeld darin Erzeugen. 
*@param String JoeStudent
**/

	public Jumpbox(String joeStudent)
	{
		fenster = new Frame(joeStudent + " Spielzeit: " +spielzeit / 1000 +"s");
		init();
	} // Jumpbox


/*****************************************************************************/
/** 
* init Uebernimmt, was in allen Konstruktoren ausgefuehrt werden soll.
* Unteranderem weredn hier die EventListener implementiert.
**/

	private void init()
	{
		setBackground(hG);
		zufall other= new Random(System.currentTimeMillis());


		bestimmeNeueRichtungsboxen();
		bestimmeNeuesZiel();
		addMouseMotionListener(this);
		fenster.addWindowListener(this);
		setSize(fBreite,fHoehe);
		fenster.setLayout(new BorderLayout());
		fenster.add("Center",this);
		fenster.pack();
		fenster.othershow();
		meinG=getGraphics();

		// Bilder laden
		Toolkit t = Toolkit.getDefaultToolkit();
		smile = t.getImage("smile.gif");
		grummel = t.getImage("wince.gif");
		startzeit = System.currentTimeMillis();
	} // init

/* Methoden des WindowListener ***********************************************/


	public void windowIconified(WindowEvent we)
	{
		stopzeit = System.currentTimeMillis();
	} // windowIconified

	public void windowClosing(WindowEvent we)
	{
		quit();
	} // windowClosing

	public void windowDeiconified(WindowEvent we)
	{
		startzeit += (System.currentTimeMillis() - stopzeit);
	} // windowDeiconified

	public void windowActivated(WindowEvent we){}
	public void windowClosed(WindowEvent we){}
	public void windowDeactivated(WindowEvent we){}
	public void windowOpened(WindowEvent we){}
	

/* Methoden des MouseMotionListener ******************************************/

/**
* wird aufgerufen, wenn die Maus mit gedr�ckter Taste �ber den Canvas bewegt
* wird
**/

	public void mouseDragged (MouseEvent e) 
	{
		if (beachteMaus)
			werteBewegungAus(e);
	} // mouseDragged

/**
* wird aufgerufen, wenn die Maus �ber den Canvas bewegt wird
**/

	public void mouseMoved(MouseEvent e) 
	{
		if (beachteMaus)
			werteBewegungAus(e);
	} // moseMoved


/* Methode die das Runnable implementiert ************************************/

	/**
	 * Die run-Methode laesst die Annimation laufen  
	 **/

	public void run()
	{
		int altx = ziel.x;
		int alty = ziel.y;

		repaint(1,kLaenge+1,fBreite-1,fHoehe-1);
		if (warTreffer)
		{
			for (int i = 2; i < 51 ; i+=2)
			{
				meinG.drawImage(smile, altx + 25 -  i/2, alty+25-i/2,i,i,this);
				try
				{
					Thread.sleep(20);
				} // try
				catch (InterruptedException ie) {}
			} // for
		} // if
		else
		{
			for (int i=50;i>0;i-=2)
			{
				meinG.drawImage(grummel,ziel.x,ziel.y,i,i,this);
				try
				{
					Thread.sleep(40);
				}
				catch (InterruptedException ie) {}

				meinG.setColor(hG);
				meinG.fillRect(altx,alty,i,i);
			} // for
		} // else
		bestimmeNeuesZiel();
		meinG.setColor(Color.black);
		meinG.otherdrawLine(altx + kLaenge / 2, alty +kLaenge /2, ziel.x + kLaenge /2, 
							ziel.y + kLaenge / 2);
		try
		{
		Thread.sleep(500);
		} // try
		catch (InterruptedException ie) {}
	} // run

/* Hier beginnen die sonstigen Methoden **************************************/

/**
 *	gibt den Spielstand aus und beendet das Programmm
**/
	
	protected void quit()
	{
		System.out.println("Ergebnis: " + punkte + " Punkte in " + 
								 spielzeit / 1000 + " Sekunden");
		System.exit(0);
	} // quit 
	

/*****************************************************************************/
/**
* Bestimme neues ziel
**/

	protected void bestimmeNeuesZiel()
	{
		int x,y;
		int wbx = fBreite - kLaenge - 2 * mA; // Erlaubte Werte fuer x  
		int wby = fHoehe - 2*kLaenge - 2 * mA; // Erlaubte Werte fuer y
		aI = Math.abs(zufall.nextInt())%4; // Neuer Richtungsindex 
		do 
		{
			// bestimme neue x-Koordinate
	 		x = Math.abs(zufall.nextInt())%wbx + mA; 
			// bestimme neue y-Koordinate
			y = Math.abs(zufall.nextInt())%wby + mA + kLaenge; 
		} while( ziel.x > x - 2*kLaenge && ziel.x < x + 2*kLaenge &&
					ziel.y > y - 2*kLaenge && ziel.y < y + 2*kLaenge);
		// while-Bedingung, weil es keinen Spass macht, mit dem Mauszeiger gleich
		// im Intimbereich des neuen Kaestchens zu sein. 
		ziel.setLocation(x,y);
	} // bestimme Neues Ziel

/**
 * wie der Name schon sagt
**/

	protected void bestimmeNeueRichtungsboxen()
	{
		// nicht besonders elegant, aber geht.	
		ia[0] = Math.abs(zufall.nextInt())%8;
		ia[1] = ia[0];
		while (ia[0] == ia[1])
			ia[1] = Math.abs(zufall.nextInt())%8;
		ia[2] = ia[0];
		while (ia[0]==ia[2] || ia[1]==ia[2])
			ia[2] = Math.abs(zufall.nextInt())%8;
		ia[3] = ia[0];
		while (ia[0]==ia[3] || ia[1]==ia[3] || ia[2]==ia[3])
			ia[3] = Math.abs(zufall.nextInt())%8;
	} // bestimmeNeueRichtungsboxen


/*****************************************************************************/
/**
* werteBewegungAus wird nach jeder Mausbewegung im Spielfeld aufgerufen, und
* pr�ft, ob die Neue Position des Zeigers ein Treffer, ein Faul oder
* nix ist.
**/

	protected void werteBewegungAus(MouseEvent e)
	{
		if (System.currentTimeMillis() - startzeit > spielzeit)	
			quit();
		Point p = e.getPoint();
		if (ziel.contains(p))
		{
			warTreffer=true;
			punkte ++;
			anzZuege++;
			starteAnnimation();
		} // if 
		else if (inIntimbereich(p))
		{
			warTreffer=false;
			punkte --;
			anzZuege ++;
			starteAnnimation();
		} // if
	} // werteBewegungAus

/** 
* Schaltet zuerst die Beachtung der Maus ab, erzeugt dann einen neuen 
* Annimationsthread und wartet dann auf das Sterben dieses Threads.
* Dann wird die Beachtung der Maus wieder eingeschaltet und
* am Ende wird dann das neue Ziel bestimmt und gezeichnet
**/

	protected void starteAnnimation()
	{
		beachteMaus=false;		// Maus ab jetzt ignorieren
		Thread t = new Thread(this);
		t.start();
		try
		{
			t.join();
		}
		catch (InterruptedException ie)
		{
			System.out.println("Wer st�rt?");
		}
		beachteMaus=true;			// ab jetzt Maus wieder beachten
		// Nach zwei Zuegen neue Richtungsboxen ist gleich wie
		// vor jedem dritten
		if (anzZuege % 2 == 0)
		{
			bestimmeNeueRichtungsboxen();
 			zeichneRichtungsboxen(meinG, rb, ia, 0, 0, kLaenge);	
		} // if
		meinG.setColor(farben[aI]);
		meinG.fillRect(ziel.x,ziel.y,kLaenge,kLaenge);
		
	} // starteAnnimation


/*****************************************************************************/
/** 
 * �berpr�ft, ob sich der Zeiger schon auf kLaenge genaehert hat    
**/

	protected boolean inNaehe(Point p)
	{
		boolean res = false;
		if((p.x < ziel.x + 2*kLaenge) && (p.x > ziel.x - kLaenge) 
			&& (p.y < ziel.y + 2*kLaenge) && (p.y > ziel.y - kLaenge))
			res=true;   
		
		return res;
	} //inNaehe

/**
* schaut nach ob der Punkt p im Intimbereich liegt
*@param Punkt p
**/

	protected boolean inIntimbereich(Point p)
	{
		boolean res = false;
		if (inNaehe(p)) 	
		{
			res=true;
			if((aI==0) && (p.x < ziel.x) && !((p.y < ziel.y) 
								|| (p.y > ziel.y +kLaenge)))
				res=false;
			if((aI==1) && (p.x > ziel.x + kLaenge-1) && !((p.y < ziel.y) 
								|| (p.y > ziel.y +kLaenge)))
				res=false;
			if((aI==2) && (p.y < ziel.y) && !((p.x < ziel.x) 
								|| (p.x > ziel.x +kLaenge)))
				res=false;
			if((aI==3) && (p.y > ziel.y + kLaenge-1) && !((p.x < ziel.x) 
								|| (p.x > ziel.x +kLaenge)))
				res=false;
		} // if
		return res;
	
	} // inIntimbereich


/*****************************************************************************/
/* Hier beginnen die Malmethoden                                             */
/*****************************************************************************/
/**
* �berschriebene paintmethode, sollte das Spielfeld malen
**/

	public void paint(Graphics g)
	{
		zeichneRichtungsboxen(g, rb, ia,0,0,kLaenge); 
		g.setColor(Color.black);
		g.drawRect(0,kLaenge,fBreite, fHoehe - kLaenge);
		g.setColor(farben[ia[aI]]);
		g.fillRect(ziel.x, ziel.y, kLaenge, kLaenge);
	} // paint


/*****************************************************************************/
/**
* zeichnet in ein Quadrat mit der linken oberen Ecke in x,y und der 
* Kantenlaenge laenge, den Buchstaben b in die Mitte 
* @param Graphicsobjekt, x,y, L�nge, Buchstabe
**/

	public void buchstabeInsQuadrat (Graphics g, String b, int x, int y, 
												int laenge)	
	{
		g.setFont(standartSchrift);
		g.setColor(Color.black);
		FontMetrics fm = getFontMetrics(standartSchrift);
		x += (laenge  - fm.stringWidth(b)) / 2;
		y += (laenge  + fm.getHeight()) / 2;
		g.otherdrawString(b, x, y); 
	} // buchstabeInsQUadrat

/*****************************************************************************/
/**
* zeichnet die Richtungsboxen in die Richtungsskala  
* @param Graphicsobjekt, String[] mit Richtungsbuchstaben, int[] fi Farbinices
* int x, int y, int laenge 
**/

	public void zeichneRichtungsboxen(Graphics g, String[] richtungen, int[] fi,
												 int x, int y, int laenge)
	{
		for (int i=0 ; i < 4 ; i ++)
		{
			g.setColor(farben[fi[i]]);
			g.fillRect( x + i*laenge, y, laenge,laenge );
			buchstabeInsQuadrat(g, richtungen[i], x + i*laenge, y, laenge); 
		} // for
	} // zeichneRichtungen


/*****************************************************************************/
/**
* Die Mainmethode uebernimmt die koordination von Jumpbox
**/

	public static void main(String[] args)
	{
		if (args.length != 0)
		try
		{
		spielzeit = (int) Integer.valueOf(args[0]).intValue() * 1000;
		} // try
		catch (NumberFormatException n)
		{
			System.err.println("Schlechtes Argument, laesst sich nicht" + 
									 " in int konvertieren");
		} // catch
			
		j = new Jumpbox(joeStudent);
	} // main
} // class