package djh.games.pavajong ; import java.awt.*; import java.util.*; // // This code is released into the public domain as of 3/31/96. // d.j.hudek // /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // class PlayBall /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // // A PlayBall is basically a square object which has // size, position, current velocity, and // qualitative speed quality (gradations of "fast") // // One can optionally elect to have old ball image information // saved for future "erasing" when the current position is painted. // This would be used if one chose to animate using an // erase old/paint new ball scheme (as opposed to a // repaint the entire background/paint new ball scheme) // public class PlayBall { ///////////////////////////////////////////////////////////////// // Class Data ///////////////////////////////////////////////////////////////// // // state values for current speed // public static final int SLOW = 0; public static final int KINDA_FAST = 1; public static final int SORTA_FAST = 2; public static final int FAST = 3; public static final int REALLY_FAST = 4; // // ratio values for speed increase category // ball changes color the faster it goes // protected static final float R_KINDA_FAST = 1.25f; protected static final float R_SORTA_FAST = 1.75f; protected static final float R_FAST = 2.25f; protected static final float R_REALLY_FAST = 2.50f; // // colors for different speed categories // (SLOW uses the default color for the Graphic) // protected static Color C_KINDA_FAST = Color.blue; protected static Color C_SORTA_FAST = Color.cyan; protected static Color C_FAST = Color.magenta; protected static Color C_REALLY_FAST = Color.red; // // default values // protected static final int DEF_BALL_SIZE = 4; protected static final float NOVICE_VX = 0.07f; protected static final float NOVICE_VY = 0.007f; protected static final float INTERMEDIATE_VX = 0.12f; protected static final float INTERMEDIATE_VY = 0.01f; protected static final float EXPERT_VX = 0.2f; protected static final float EXPERT_VY = 0.02f; protected static final float DEF_INIT_VEL_X = INTERMEDIATE_VX; protected static final float DEF_INIT_VEL_Y = INTERMEDIATE_VY; protected static final int DEF_OLDBALLDATA_VECTOR_SIZE = 5; ///////////////////////////////////////////////////////////////// // Instance Variables ///////////////////////////////////////////////////////////////// protected float initVelocityX; protected float initVelocityY; protected float velocityX; protected float velocityY; protected int size; protected float currentX; protected float currentY; protected boolean shouldSaveOldData; // for future erasing protected Vector toBeErasedVector; ///////////////////////////////////////////////////////////////// // Constructors ///////////////////////////////////////////////////////////////// /** * A ball which has size, position, current velocity, and * current "speed quality" state (gradations of "fast") * * This constructor will use default values for velocity and size * * @param x - initial x position * @param y - initial y position */ public PlayBall( float x, float y ) { initVelocityX = DEF_INIT_VEL_X; initVelocityY = DEF_INIT_VEL_Y; velocityX = initVelocityX; velocityY = initVelocityY; currentX = x; currentY = y; size = DEF_BALL_SIZE; shouldSaveOldData = true; toBeErasedVector = new Vector( DEF_OLDBALLDATA_VECTOR_SIZE ); } /** * A ball which has size, position, current velocity, and * current "speed quality" state (gradations of "fast") * * This constructor will use default value for size * * @param x - initial x position * @param y - initial y position * @param dL - difficulty level used to determine initial * ball velocity (higher difficulty --> faster velocity) */ public PlayBall( float x, float y, DifficultyLevel dL ) { currentX = x; currentY = y; size = DEF_BALL_SIZE; setVelocities( dL ); shouldSaveOldData = true; toBeErasedVector = new Vector( DEF_OLDBALLDATA_VECTOR_SIZE ); } /** * A ball which has size, position, current velocity, and * current "speed quality" state (gradations of "fast") * * @param x - initial x position * @param y - initial y position * @param sz - size of ball * @param dL - difficulty level used to determine initial * ball velocity (higher difficulty --> faster velocity) */ public PlayBall( float x, float y, int sz, DifficultyLevel dL ) { currentX = x; currentY = y; size = sz; setVelocities( dL ); shouldSaveOldData = true; toBeErasedVector = new Vector( DEF_OLDBALLDATA_VECTOR_SIZE ); } /** * A ball which has size, position, current velocity, and * current "speed quality" state (gradations of "fast") * * This constructor will use default value for size * * @param x - initial x position * @param y - initial y position * @param vX - initial velocity in the x direction * @param vY - initial velocity in the y direction */ public PlayBall( float x, float y, float vX, float vY ) { initVelocityX = vX; initVelocityY = vY; velocityX = initVelocityX; velocityY = initVelocityY; currentX = x; currentY = y; size = DEF_BALL_SIZE; shouldSaveOldData = true; toBeErasedVector = new Vector( DEF_OLDBALLDATA_VECTOR_SIZE ); } /** * A ball which has size, position, current velocity, and * current "speed quality" state (gradations of "fast") * * @param x - initial x position * @param y - initial y position * @param vX - initial velocity in the x direction * @param vY - initial velocity in the y direction * @param sz - size of ball */ public PlayBall( float x, float y, float vX, float vY, int sz ) { initVelocityX = vX; initVelocityY = vY; velocityX = initVelocityX; velocityY = initVelocityY; currentX = x; currentY = y; size = sz; shouldSaveOldData = true; toBeErasedVector = new Vector( DEF_OLDBALLDATA_VECTOR_SIZE ); } ///////////////////////////////////////////////////////////////// // Methods ///////////////////////////////////////////////////////////////// //////////////////////// ///// private method... ///// Given a difficulty level, set the initial velocity //////////////////////// private void setVelocities( DifficultyLevel dL ) { initVelocityX = dL.isExpert() ? EXPERT_VX : (dL.isIntermediate() ? INTERMEDIATE_VX : NOVICE_VX); initVelocityY = dL.isExpert() ? EXPERT_VY : (dL.isIntermediate() ? INTERMEDIATE_VY : NOVICE_VY); velocityX = initVelocityX; velocityY = initVelocityY; } /** * returns the size of the ball */ public int getSize() { return( size ); } /** * returns the current x position of the ball */ public float getX() { return( currentX ); } /** * returns the current y position of the ball */ public float getY() { return( currentY ); } /** * Sets the X and Y coordinates for the ball, * * @param x - desired x position * @param y - desired y position */ public void setXY( float x, float y ) { currentX = x; currentY = y; } /** * Sets whether or not to save old ball positional data * (for use with eraseOld()) * * @param saveItFlag - if true, old data will be saved * for later use with future image erasing * * @see #eraseOld * @see #areSavingData * @see #flushOldData */ public void setSaveOldData( boolean saveItFlag ) { shouldSaveOldData = saveItFlag; } /** * Returns true if are currently saving old ball positional data * * @see #setSaveOldData * @see #flushOldData * @see #eraseOld */ public boolean areSavingData() { return( shouldSaveOldData ); } /** * Flushes the vector holding old ball positional information * (used by eraseOld()) * * @see #eraseOld * @see #setSaveOldData */ public void flushOldData() { toBeErasedVector.removeAllElements(); } /** * returns the current velocity in the x dimension */ public float getVx() { return( velocityX ); } /** * set the current velocity in the x dimension * @param vX - desired velocity in the x dimension */ public void setVx( float vX ) { velocityX = vX; } /** * reverses the ball's x velocity */ public void invertVx() { velocityX = -velocityX; } /** * returns the current velocity in the y dimension */ public float getVy() { return( velocityY ); } /** * set the current velocity in the y dimension * @param vY - desired velocity in the y dimension */ public void setVy( float vY ) { velocityY = vY; } /** * reverses the ball's y velocity */ public void invertVy() { velocityY = -velocityY; } /** * Returns a value that gives a qualitative assessment of * the ball's current velocity. The value returned is * one of the relevant values defined as public class data: * SLOW, KINDA_FAST, SORTA_FAST, FAST, REALLY_FAST. * * The algorithm is permissive, using the highest of * the two velocity components. */ public int howFast() { int speedQuality = SLOW; float vxRatio; float vyRatio; vxRatio = Math.abs(velocityX/initVelocityX); vyRatio = Math.abs(velocityY/initVelocityY); if( (vxRatio > R_REALLY_FAST) || (vyRatio > R_REALLY_FAST) ) { speedQuality = REALLY_FAST; } else if( (vxRatio > R_FAST) || (vyRatio > R_FAST) ) { speedQuality = FAST; } else if( (vxRatio > R_SORTA_FAST) || (vyRatio > R_SORTA_FAST) ) { speedQuality = SORTA_FAST; } else if( (vxRatio > R_KINDA_FAST) || (vyRatio > R_KINDA_FAST) ) { speedQuality = KINDA_FAST; } else { speedQuality = SLOW; } return( speedQuality ); } /** * Paints the ball at its current location with * color appropriate to its current speed. * * It conditionally saves the position/size data * for later use in erasing this image * (e.g., if erase old/paint new animation is to be * used [as opposed to repaint the entire background/ * paint new ball]) * * @param - theG Graphics within which to paint * * @see #setSaveOldData * @see #eraseOld */ public synchronized void paintCurrent( Graphics theG ) { boolean colorChange; Color saveGraphicsColor; int speedQuality; if( shouldSaveOldData ) { toBeErasedVector.addElement( new Rectangle((int)currentX, (int)currentY, size, size) ); } // alter ball color if it's moving > SLOW colorChange = true; // assume, then change if necessary saveGraphicsColor = theG.getColor(); switch( howFast() ) { case REALLY_FAST: theG.setColor( C_REALLY_FAST ); break; case FAST: theG.setColor( C_FAST ); break; case SORTA_FAST: theG.setColor( C_SORTA_FAST ); break; case KINDA_FAST: theG.setColor( C_KINDA_FAST ); break; case SLOW: default: colorChange = false; break; } theG.fillRect( (int)currentX, (int)currentY, size, size ); if( colorChange ) { // restore original color theG.setColor( saveGraphicsColor ); } } /** * Paints the old ball position(s) with the specified color * (which should be the current background color) * * @param theG - Graphics within which to paint * @param backgroundColor - Color to use in painting over * the old ball location */ public synchronized void eraseOld( Graphics theG, Color backgroundColor ) { if( !(toBeErasedVector.isEmpty()) ) { Enumeration oldBalls; Rectangle ball; Color saveColor; oldBalls = toBeErasedVector.elements(); saveColor = theG.getColor(); theG.setColor( backgroundColor ); while( oldBalls.hasMoreElements() ) { ball = (Rectangle)(oldBalls.nextElement()); theG.fillRect( ball.x, ball.y, ball.width, ball.height ); } theG.setColor( saveColor ); toBeErasedVector.removeAllElements(); } } }