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;
}
}