package djh.games.pavajong ; import java.awt.*; // // This code is released into the public domain as of 3/31/96. // d.j.hudek // /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // class Paddle /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// public class Paddle extends Canvas { protected static final int DEF_WIDTH = 25; protected static final int DEF_HEIGHT = Playground.DEF_HEIGHT; // paddle size ratio (compared to total height) // novice gets a paddle that covers 20% of range, // intermediate gets 15%, and // expert gets only 10% protected static float NOVICE_PADDLE_RATIO = 0.20f; protected static float INTERMED_PADDLE_RATIO = 0.15f; protected static float EXPERT_PADDLE_RATIO = 0.10f; ///////////////////////////////////////////////////////////////// // Instance Variables ///////////////////////////////////////////////////////////////// protected boolean amISlave; protected Paddle mySlave; // For now, just have one. protected boolean gotMouse; // Used for slaving... // only follow mouse if // master has it protected float paddleYprop; // height of paddle as // ratio of total height // Master gets mouse x and y coordinates from event handler // Slave gets the info from its setX and setY methods // (called from the master) // // In this first version, we only care about the Y value... // we don't care about the X ... it's a placeholder // for the future when we may wish to allow a paddle // to provide more or less "oomph" when a ball hits // depending on various algorithms which use the X information protected int mouseX = 0; // For now,don't care. protected int mouseY = 0; // Do care. paddle // follows this. // save initial foreground and background colors to allow // color change alerting // background color also used in graphics double-buffer // to fill in background in off-screen image protected boolean gotColors; protected Color saveFColor; protected Color saveBColor; protected boolean paintFunnyColors; // off-screen buffers to improve animation private Image bufferImage = null; private Graphics bufferGraphics = null; private Dimension bufferGSize = null; ///////////////////////////////////////////////////////////////// // Constructors ///////////////////////////////////////////////////////////////// /** * Instantiates a slave Paddle who's motion will be slaved * to some other (master) Paddle * * The paddle will be created with default size */ public Paddle() { // with no arguments indicates slave amISlave = true; mySlave = null; gotMouse = false; gotColors = false; paintFunnyColors = false; paddleYprop = INTERMED_PADDLE_RATIO; } /** * Instantiates a master Paddle * * It will be created with default size. * * @param aSlave - the paddle who's motion is slaved to the * master paddle being instantiated. */ public Paddle( Paddle aSlave ) { amISlave = false; mySlave = aSlave; gotMouse = false; gotColors = false; paintFunnyColors = false; paddleYprop = INTERMED_PADDLE_RATIO; } /** * Instantiates a slave Paddle who's motion will be slaved * to some other (master) Paddle * * @param pDL - DifficultyLevel used in determining * the size of the paddle. * */ public Paddle( DifficultyLevel pDL ) { // with no arguments indicates slave amISlave = true; mySlave = null; gotMouse = false; gotColors = false; paintFunnyColors = false; if( pDL.isExpert() ) { paddleYprop = EXPERT_PADDLE_RATIO; } else if( pDL.isIntermediate() ) { paddleYprop = INTERMED_PADDLE_RATIO; } else { paddleYprop = NOVICE_PADDLE_RATIO; } } /** * Instantiates a master Paddle * * @param aSlave - the paddle who's motion is slaved to the * master paddle being instantiated. * @param pDL - DifficultyLevel used in determining * the size of the paddle. */ public Paddle( Paddle aSlave, DifficultyLevel pDL ) { amISlave = false; mySlave = aSlave; gotMouse = false; gotColors = false; paintFunnyColors = false; if( pDL.isExpert() ) { paddleYprop = EXPERT_PADDLE_RATIO; } else if( pDL.isIntermediate() ) { paddleYprop = INTERMED_PADDLE_RATIO; } else { paddleYprop = NOVICE_PADDLE_RATIO; } } ///////////////////////////////////////////////////////////////// // Methods ///////////////////////////////////////////////////////////////// /** * setX * sets paddle x position * * @param x - desired x postion */ public void setX( int x ) { mouseX = x; } /** * setY * sets paddle y position * * @param y - desired y postion */ public void setY( int y ) { mouseY = y; } /** * Check to see if some other item has hit this paddle. * If it did, it sets the paddle region to indicate where. * * @param themYstart - starting Y position for other object * @param themYend - ending Y position for other object * @param pr - PaddleRegion which, if there was a hit, * will indicate where */ public boolean hitPaddle( int themYstart, int themYend, PaddleRegion pr ) { int h = size().height; int paddleYsize = (int)( (float)h * paddleYprop ); int startY; int endY; // // find range of "paddle" based on current mouse position // startY = mouseY - (paddleYsize/2); if( startY < 0 ) { startY = 0; } else if( startY > (h - paddleYsize) ) { startY = (h - paddleYsize); } endY = startY + paddleYsize; if( (themYend < startY) || (themYstart > endY) ) { // System.out.println("Missed!"); return( false ); } else { // System.out.println("Hit it!"); // Set Region based on their "middle" pr.setRegion( startY, endY, (themYstart + themYend)/2 ); return( true ); } } /////////////////////// ///// private method... ///// helper function called by mouseMove or mouseDrag. ///// Paddle position follows the mouse position as long ///// as the mouse is within the paddle region /////////////////////// private boolean handleMouseMoveOrDrag( int x, int y ) { if( gotMouse ) { mouseX = x; mouseY = y; repaint(); if( mySlave != null ) { mySlave.setX( x ); mySlave.setY( y ); mySlave.repaint(); } } return( true ); } ////////////////// Overridden Methods /////////////////// /** * Paddle movement is controlled by mouse movement within the * master paddle region. Sets internal state when mouse * is within master paddle. If it is within the slave * paddle region, gives visual feedback of error */ public boolean mouseEnter( Event evt, int x, int y ) { if( amISlave ) { // silly user... mouse does no good over here. // Alert via painting in unusual colors paintFunnyColors = true; repaint(); } else { gotMouse = true; } return( true ); } /** * Paddle movement is controlled by mouse movement within the * master paddle region. Sets internal state when mouse * leaves region. If it was (erroneously) within the slave * paddle region, set colors back to normal now * that they're leaving. */ public boolean mouseExit( Event evt, int x, int y ) { gotMouse = false; if( amISlave ) { paintFunnyColors = false; } repaint(); return( true ); } /** * Adjust Paddle position based on mouse movement * Paddle tracks the mouse as long as it's within * the paddle region of a master paddle. */ public boolean mouseMove( Event evt, int x, int y ) { return( handleMouseMoveOrDrag(x,y) ); } /** * Adjust Paddle position based on mouse movement * Paddle tracks the mouse as long as it's within * the paddle region of a master paddle. */ public boolean mouseDrag( Event evt, int x, int y ) { return( handleMouseMoveOrDrag(x,y) ); } /** * Use double-buffering to reduce flickering. * Set up off-screen buffer, paint it, then draw that image * to the screen */ public synchronized void update( Graphics theG ) { Dimension d = size(); Color saveGraphicsColor = theG.getColor(); if( !gotColors ) { // foreground and background colors // used in mouseEnter(),mouseExit() // // background color used here to paint // background in offscreen image saveFColor = getForeground(); saveBColor = getBackground(); gotColors = true; } if( (bufferImage == null) || (d.width != bufferGSize.width) || (d.height != bufferGSize.height) ) { bufferImage = createImage(d.width, d.height); bufferGraphics = bufferImage.getGraphics(); bufferGraphics.setFont( getFont() ); bufferGSize = d; } if( paintFunnyColors ) { bufferGraphics.setColor( Color.black ); bufferGraphics.fillRect( 0, 0, d.width, d.height ); bufferGraphics.setColor( Color.red ); paint( bufferGraphics ); theG.drawImage( bufferImage, 0, 0, null ); } else { bufferGraphics.setColor( saveBColor ); bufferGraphics.fillRect( 0, 0, d.width, d.height ); bufferGraphics.setColor( saveGraphicsColor ); paint( bufferGraphics ); theG.drawImage( bufferImage, 0, 0, null ); } } /** * Draw "paddle" image based on current position */ public synchronized void paint( Graphics theG ) { int w = size().width; int h = size().height; int paddleYsize = (int)( (float)h * paddleYprop ); int paddleXsize = w; // initial version, paddle will // take up the entire width int startX; int startY; // // draw "paddle" based on current mouse position // The middle of the paddle follows the mouse cursor // but cannot exceed the boundaries // startY = mouseY - (paddleYsize/2); if( startY < 0 ) { startY = 0; } else if( startY > (h - paddleYsize) ) { startY = (h - paddleYsize); } startX = w - paddleXsize; theG.drawRect( 0, 0, w-1, h-1 ); theG.fillRect( startX, startY, paddleXsize, paddleYsize ); } public Dimension minimumSize() { return( new Dimension(DEF_WIDTH,DEF_HEIGHT) ); } public Dimension preferredSize() { return( minimumSize() ); } }