paddle.java

//******************************************************************************
// paddle.java:	Applet
//
// paddle - Yet another paddle/pong game (Version 1.0)
// Author - Mario Giannini 9/22/97
// This Paddle game was developed with Visual J++, though very little of
// J++'s features where used.
//******************************************************************************
import java.applet.*;
import java.awt.*;
import java.util.*;

//==============================================================================
// Main Class for applet paddle
//
//==============================================================================
public class paddle extends Applet implements Runnable
{
	// thrdPaddle is the thread.  Animation is done via threading
	Thread	 thrdPaddle = null;

	// Support for the graphic items
	private Graphics gGraphics;	// The Java Graphics object
	private Image    imgPaddle;	// Image for the paddle
	private Image    imgDigits[];	// Images for the 'LED' digits
	private int 	 nPaddleWidth  = 0; // Paddle height
	private int 	 nPaddleHeight = 0; // Paddle Width
	private boolean  fAllLoaded = false; // True if all images are done loading

	Random Rand;						// Java Random number generator class
	int nSpeedY = 0, nSpeedX = 0;		// Ball speed, X and Y
	int nLastBallX = 0, nLastBallY = 0;	// Last ball position, X and Y
	int nBallY = 0, nBallX = 0;			// Current Ball position, X and Y
	int nLastPaddleX = 0, nPaddleX = 0;	// Current and last Paddle X (Y is fixed)
	int nPlayY=0;						// Divides client into play and score area
	int nScore=0;						// Current Score
	int nLastScore=-1;					// Last Score (used to determine if score should be re-displayed)
	int nBallCount=3;					// Current Ball count
	int nLastBallCount=-1;				// Last ball count (used to determine if ball count should be re-displayed)
	int nDigitWidth=0;					// Width of 'LED' digit images
	int nConsecutive=0;					// Consecutive scores, for a 'climbing' score
	boolean fSuspended = true;			// Game play is either suspended, or it isn't
	boolean fMouseLeft = false;

	// MoveBall - Determine next location of Ball.  Handles ball bounce
	void MoveBall() 
	{
		if( nBallX + nSpeedX <=0 )
		{
			nSpeedX = (Rand.nextInt() % 20)+20;
			nBallX=0;
		}
		else
		if( nBallX + nSpeedX >= size().width-20 )
		{
			nSpeedX = -(Rand.nextInt() % 20 +20);
			nBallX = size().width-20;
		}
		else
			nBallX = nBallX + nSpeedX;


		if( nBallY + nSpeedY <=0 )
		{
			nSpeedY = (Rand.nextInt() % 20)+20;
			nBallY=0;
			nScore+=nConsecutive;
			if( nConsecutive==0 )
				nConsecutive=1;
			else
				nConsecutive *= 2;
		}
		else
		if( nBallY + nSpeedY+20 >= nPlayY-nPaddleHeight && nBallX>=nPaddleX && nBallX+20<nPaddleX+nPaddleWidth )
		{
			nSpeedY = -(Rand.nextInt() % 20 +20);
			nBallY = (nPlayY-nPaddleHeight)-20;
		}
		else 
		if( nBallY + nSpeedY >= nPlayY-20 )
		{
			nSpeedY = -(Rand.nextInt() % 20 +20);
			nBallY = nPlayY-20;
			if( nBallCount>0 )
				nBallCount--;
			nConsecutive = 1;
			fSuspended = true;
		}
		else
			nBallY = nBallY + nSpeedY;
	}

	

	// Paddle Class Constructor
	//--------------------------------------------------------------------------
	public paddle()
	{
		Rand = new Random();
	}

	// APPLET INFO SUPPORT:
	//		The getAppletInfo() method returns a string describing the applet's
	// author, copyright date, or miscellaneous information.
    //--------------------------------------------------------------------------
	public String getAppletInfo()
	{
		return "Name: Paddle\r\nAuthor: Mario\r\n";
	}


	// The init() method is called by the AWT when an applet is first loaded or
	// reloaded.  
    //--------------------------------------------------------------------------
	public void init()
	{
        resize(320, 300);
	}

	// Place additional applet clean up code here.  destroy() is called when
	// when you applet is terminating and being unloaded.
	//-------------------------------------------------------------------------
	public void destroy()
	{
		// No need to destroy Rand, this is Java, not C++
	}

	// ShowBallCount - Displays numeric for BallCount using 'LED' images
	void ShowBallCount( Graphics g )
	{
		g.drawImage( imgDigits[nBallCount], size().width-nDigitWidth*2, nPlayY+1, null );
	}

	// ShowScore - Displays numeric for Score using 'LED' images
	void ShowScore( Graphics g ) 
	{
		int M, HTh, TTh, Th, H, T, O;
		
		M =   (nScore/1000000)%10;
		HTh = (nScore/100000)%10;
		TTh = (nScore/10000)%10;
		Th = (nScore/1000)%10;
		Th = (nScore/1000)%10;
		H = (nScore/100)%10;
		T = (nScore/10)%10;
		O = (nScore/1)%10;
		g.drawImage( imgDigits[M], nDigitWidth*1, nPlayY+1, null );
		g.drawImage( imgDigits[HTh], nDigitWidth*2, nPlayY+1, null );
		g.drawImage( imgDigits[TTh], nDigitWidth*3, nPlayY+1, null );
		g.drawImage( imgDigits[Th], nDigitWidth*4, nPlayY+1, null );
		g.drawImage( imgDigits[H], nDigitWidth*5, nPlayY+1, null );
		g.drawImage( imgDigits[T], nDigitWidth*6, nPlayY+1, null );
		g.drawImage( imgDigits[O], nDigitWidth*7, nPlayY+1, null );
	}

    //  updateScreen - Refreshes screen contents for ball, paddle, and score
	//--------------------------------------------------------------------------
	private void updateScreen(Graphics g)
	{
		if (!fAllLoaded)
			return;
		
		Rectangle r = g.getClipRect();
		if( nLastPaddleX!=nPaddleX )
		{
			g.setColor( Color.white );
			g.fillRect( nLastPaddleX, nPlayY - nPaddleHeight, nPaddleWidth, nPaddleHeight );
			g.setColor( Color.black );
			nLastPaddleX=nPaddleX;
			g.drawImage(imgPaddle, nLastPaddleX, nPlayY - nPaddleHeight, null);
		}
		
		g.setColor( Color.white );
		g.fillRect( nLastBallX, nLastBallY, 21, 21 );
		g.setColor( Color.black );
		nLastBallX = nBallX;
		nLastBallY = nBallY;
		g.fillOval( nLastBallX, nLastBallY,20, 20 );
		g.drawLine( 0, nPlayY, size().width-1, nPlayY );
		if( nScore != nLastScore )
		{
			ShowScore(g);
			nLastScore = nScore;
		}
		if( nBallCount != nLastBallCount )
		{
			ShowBallCount( g );
			nLastBallCount = nBallCount;
		}
	}

	// Paddle Paint Handler
	//--------------------------------------------------------------------------
	public void paint(Graphics g)
	{
		if (fAllLoaded)	// Determine if images are still loading
		{
			Rectangle r = g.getClipRect();
			g.setColor( Color.white );
			g.fillRect(r.x, r.y, r.width, r.height);
			updateScreen(g);
		}
		else
			g.drawString("Loading images...", 10, 20);
	}

	//		The start() method is called when the page containing the applet
	// first appears on the screen. 
	//--------------------------------------------------------------------------
	public void start()
	{
		// Start the thread executing
		if (thrdPaddle == null)
		{
			thrdPaddle = new Thread(this);
			thrdPaddle.start();
		}
	}
	
	//		The stop() method is called when the page containing the applet is
	// no longer on the screen. 
	//--------------------------------------------------------------------------
	public void stop()
	{
		if (thrdPaddle != null) // Stop the thread
		{
			thrdPaddle.stop();
			thrdPaddle = null;
		}
	}

	// THREAD SUPPORT
	//		The run() method is called when the applet's thread is started.
	//      This is the thread that runs the game
	//--------------------------------------------------------------------------
	public void run()
	{
		int nCurrImage = 0;
		String strImage;
		
		// If re-entering the page, then the images have already been loaded.
		// fAllLoaded == TRUE.
		//----------------------------------------------------------------------
        if (!fAllLoaded)
		{
    		repaint();
    		gGraphics = getGraphics();
			gGraphics.setColor( Color.white );
		    		
    		// Load in all the images
    		//------------------------------------------------------------------
    		MediaTracker tracker = new MediaTracker(this);
    		
    		imgPaddle = getImage(getDocumentBase(), "images/paddle.gif");
			tracker.addImage(imgPaddle, 0);
			imgDigits = new Image[10];
			for( nCurrImage=0; nCurrImage<10; nCurrImage++ )
			{
				strImage = "images/dig_"+String.valueOf(nCurrImage) + ".gif";
				imgDigits[nCurrImage] = getImage( getDocumentBase(), strImage );
				tracker.addImage( imgDigits[nCurrImage],0 );
			}
            // Wait until all images are fully loaded
    		//------------------------------------------------------------------
			try
			{
				tracker.waitForAll();
				fAllLoaded = !tracker.isErrorAny();
			}
			catch (InterruptedException e)
			{
				// We'll do nothing here.  It's graceful error-recovery.
				// Note that the thread may have been stoped during the
				// sleep, which would trigger this exception
			}
			
			
			if (!fAllLoaded)	// Report any loading errors
			{
			    gGraphics.drawString("Error loading images!", 10, 40);
			    return;
			}
			
			// Determine window dimensions
			nPlayY = size().height - (imgDigits[0].getHeight(this));
			nDigitWidth = imgDigits[0].getWidth(this);
    		nPaddleWidth  = imgPaddle.getWidth(this);
		    nPaddleHeight = imgPaddle.getHeight(this);
        }		
		repaint();

		// This is the main part of the game.  Where the 'thread' runs
		while (true)
		{
			try
			{
				if( fSuspended == false && fMouseLeft==false)	// fSuspended determines if anything happens
				{
					updateScreen(gGraphics);
					MoveBall();
				}
				Thread.sleep(50);
			}
			catch (InterruptedException e)
			{
				stop();
			}
		}
	}

	// MOUSE SUPPORT:
	//		The mouseMove() method is called if the mouse cursor moves over the
	// applet's portion of the screen and the mouse button isn't being held down.
	//--------------------------------------------------------------------------
	public boolean mouseMove(Event evt, int x, int y)
	{
		if( y > nPlayY - nPaddleHeight && y < nPlayY)
			nPaddleX = x-(nPaddleWidth/2);
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseUp() method is called if the mouse button is released
	// while the mouse cursor is over the applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseUp(Event evt, int x, int y)
	{
		// TODO: Place applet mouseUp code here
		if( fSuspended==true )
		{
			if( nBallY!=0 )
			{
				nBallX = (Rand.nextInt()%size().width-40)+20;
				nBallY = 0;
				nConsecutive = 0;
			}
			if( nBallCount==0 )
			{
				nBallCount=3;
				nScore=0;
				nLastScore=-1;
				repaint();
			}
			else
				fSuspended = false;
		}
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseEnter() method is called if the mouse cursor enters the
	// applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseEnter(Event evt, int x, int y)
	{
		fMouseLeft = false;
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseExit() method is called if the mouse cursor leaves the
	// applet's portion of the screen.
 	//--------------------------------------------------------------------------
	public boolean mouseExit(Event evt, int x, int y)
	{
		fMouseLeft = true;
		return true;
	}
}