/*
   THIS IS A REALLY STUPID APPLET THAT JUST DRAWS AN X.
   VERY BORING, REALLY.  I'M SURE YOU CAN DO MUCH BETTER. :-)
*/

import java.awt.*;
import java.util.Random;

public class JumpBot extends BufferedApplet
{
	final int APPLET_HEIGHT = 599;
	final int APPLET_WIDTH = 399;
	
	final int STATE_STANDING = 0;
	final int STATE_PREJUMP = 1;
	final int STATE_JUMP= 2;
	final int STATE_FALL = 3;
	final int STATE_LAND = 4;
	
	final int RECT_WIDTH = 40;
	final int RECT_HEIGHT = 20;
	
	final int LEG_WIDTH= 20;
	final int LEG_HEIGHT = 60;
	
	int iState = STATE_STANDING;
	int iGravity = -10;
	int iWait = 10;
	
	public int iVelocity = 0;
	public Random RandVeloGen = new Random();
	
	int iRectX = 180;
	int iRectY = APPLET_HEIGHT - RECT_HEIGHT - 20;
	
	int iLegLeftX = 140;
	int iLegLeftY = APPLET_HEIGHT - LEG_HEIGHT;
	
	int iLegRightX = 240;
	int iLegRightY = APPLET_HEIGHT - LEG_HEIGHT;   
   
   public void render(Graphics g) {

      // WHENEVER THERE IS "DAMAGE", WE NEED TO REDRAW

      if (damage) {

         // SET COLOR TO WHITE AND CLEAR THE APPLET WINDOW

         g.setColor(Color.white);
         g.fillRect(0, 0, bounds().width, bounds().height);

		UpdatePos(g);
			//update JumpBot first, then draw
				
         g.setColor(Color.blue);
         	//set color to blue to color the legs         
         g.fillRect(iLegLeftX, iLegLeftY, LEG_WIDTH, LEG_HEIGHT);
         g.fillRect(iLegRightX, iLegRightY, LEG_WIDTH, LEG_HEIGHT);
         
         g.setColor(Color.red);
         	//set color to red to color the bodyy
         g.fillRect(iRectX - 2, iRectY, RECT_WIDTH, RECT_HEIGHT);

         g.setColor(Color.black);
         	//set color to black to draw in the lines
         g.drawLine(iRectX - 2, iRectY, iLegLeftX + LEG_WIDTH, iLegLeftY);
         g.drawLine(iRectX - 2 + RECT_WIDTH, iRectY, iLegRightX, iLegLeftY);

         g.drawRect(iRectX - 2, iRectY, RECT_WIDTH, RECT_HEIGHT);
         g.drawRect(iLegLeftX, iLegLeftY, LEG_WIDTH, LEG_HEIGHT);
         g.drawRect(iLegRightX, iLegRightY, LEG_WIDTH, LEG_HEIGHT);
         	//lines of rectangles drawn after colorfill so the color doesn't
         	//overlap the lines
      }
   }
   
   public void UpdatePos(Graphics g)
   		//Updates the position of JumpBot in the applet window
   {
		if (iState == STATE_STANDING)
			//JumpBot waits 10 cycles between each jump
		{
			iWait--;
			if (iWait < 0)
				ChangeState(STATE_PREJUMP);
		}
		else if (iState == STATE_PREJUMP)
			//JumpBot prepares to jump
		{
			ChangeState(STATE_JUMP);
		}	
		else if (iState == STATE_JUMP)
			//JumpBot shoots into the air but is sucked
			//down by gravity, eventually falling
		{
			iRectY = iRectY - iVelocity;
			iLegLeftY = iLegLeftY - iVelocity;
			iLegRightY = iLegRightY - iVelocity;
			iVelocity = iVelocity + iGravity;
			if (iVelocity < 0)
				ChangeState(STATE_FALL);
		}
		else if (iState == STATE_FALL)
			//Checks to see when JumpBot hits the ground
		{
			iRectY = iRectY - iVelocity;
			iLegLeftY = iLegLeftY - iVelocity;
			iLegRightY = iLegRightY - iVelocity;
			iVelocity = iVelocity + iGravity;
			
			if ((iLegLeftY + LEG_HEIGHT) >= APPLET_HEIGHT)
			{
				iLegLeftY = APPLET_HEIGHT - LEG_HEIGHT;
				iLegRightY = APPLET_HEIGHT - LEG_HEIGHT;
				ChangeState(STATE_LAND);
			}
		}
		else if (iState == STATE_LAND)
		{
			iWait = 10;	
			ChangeState(STATE_STANDING);
   		}
   }
   
   public void ChangeState(int iNewState)
   //The legs of JumpBot remain bascially in the same position.  JumpBot's body
   //changes position to give the illusion of movement.
   //This method will alter the position of the body depending on the
   //new state that is passed in
   {
   		iState = iNewState;
   		switch (iNewState)
   		{
   			case STATE_STANDING: 	iRectY = iLegLeftY + 20; iWait = 10; break;	
   			case STATE_PREJUMP: 	GetInitVelo(); iRectY = iLegLeftY + 40 - (iVelocity/10); break;
   			case STATE_JUMP: 		iRectY = iLegLeftY - 40 - (iVelocity/10); break;
   			case STATE_FALL: 		iRectY = iLegLeftY - 20 + (iVelocity/5); break;
   			case STATE_LAND: 		iRectY = APPLET_HEIGHT - 20 + (iVelocity/10); break;
   		}
   	
   }
   
	public void GetInitVelo()
		//randomly generates numbers between 3 and 10, multiplies by 10
		//to get a good intial velocity
		//any jump with an initial velocity less than 30 looks pitiful
	{
   		iVelocity = (RandVeloGen.nextInt(7) + 3) * 10;
   	}   
}

class BufferedApplet extends java.applet.Applet implements Runnable
{
/*
   THIS CLASS HANDLES DOUBLE BUFFERING FOR YOU, SO THAT THE IMAGE
   DOESN'T FLICKER WHILE YOU'RE RENDERING IT.  YOU DON'T REALLY
   NEED TO WORRY ABOUT THIS TOO MUCH, AND YOU'LL PROBABLY NEVER NEED
   TO CHANGE IT.  IT'S REALLY JUST USEFUL LOW LEVEL PLUMBING.
*/

   public void render(Graphics g) { }   // *you* define how to render
   public boolean damage = true;        // you can force a render

   private Image image = null;
   private Graphics buffer = null;
   private Thread t;
   private Rectangle r = new Rectangle(0, 0, 0, 0);

   // A BACKGROUND THREAD CHECKS FOR CHANGES ABOUT 30 TIMES PER SECOND

   public void start() { if (t == null) { t = new Thread(this); t.start(); } }
   public void stop()  { if (t != null) { t.stop(); t = null; } }
   public void run()   { try { while (true) { repaint(); t.sleep(30); } }
                             catch(InterruptedException e){}; }
/*
   UPDATE GETS CALLED BY THE SYSTEM.
   IT CALLS YOUR RENDER METHOD, WHICH DRAWS INTO AN OFF-SCREEN IMAGE.
   THEN UPDATE COPIES THE IMAGE YOU'VE RENDERED ONTO THE APPLET WINDOW.
*/

   public void update(Graphics g) {
      if (r.width != bounds().width || r.height != bounds().height) {
         image = createImage(bounds().width, bounds().height);
         buffer = image.getGraphics();
         r = bounds();
         damage = true;
      }
      damage = true;
      render(buffer);
      
      if (image != null)
         g.drawImage(image,0,0,this);
   }
}
