import uwcse.graphics.*; import uwcse.io.Input; import java.awt.Color; import java.awt.Image; import java.util.Random; import java.io.File; /** * This is the main class for the HW3 assignment. * It creates a window, with a bounding rectangle drawn * just inside its edges, and up to two "balls" and two * "obstacles". * To run it there are a number of choices: *
is "for (...) {...}" * This method is one of several containing features of Java we have not yet studied (in this * case, "do { .... } while (....);" and "System.exit(0)"). You should not have to modify this * method, so please don't get wrapped up in the details of the statements we haven't yet seen. */ public static void main(String args[]) { BallGame bg = new BallGame(); bg.createBall( "soccer.jpg" ); bg.createBall( "tennis.jpg" ); bg.createObstacle( "house.jpg" ); bg.createObstacle( "hooch.jpg" ); Input input = new Input(); int numSteps = 0; do { numSteps = input.readInt( "Input number of steps to run (0 to quit): " ); bg.go(numSteps); } while ( numSteps > 0 ); System.exit( 0 ); } /** * Create and add the image of the ball at a randomly chosen position and with randomly * chosen initial velocity. (Nothing moves until go() is invoked, however.) *
* At most two balls can be created in the code as distributed. *
* This code will have to change only if you want to increase the maximum number of balls * allowed. *
* @param imageFileName The name of a .jpg file to use as the image for the ball. *
* @return A Player that has been assigned an initial, non-overlapping position and a non-zero * velocity. */ public Player createBall( String imageFileName ) { Random random = new Random(); Player newBall = this.createPlayer ( imageFileName, 1+random.nextInt(3), 1+random.nextInt(3) ); if ( firstBall == null ) { firstBall = newBall; } else if ( secondBall == null ) { secondBall = newBall; } else { mainWindow.print( "Full - Can't create new ball" ); return null; } if ( newBall != null ) { newBall.addToWindow( mainWindow ); } return newBall; } /** * Create and add the image an obstacle - something that doesn't move - at a randomly chosen position. *
balls * At most two obstacless can be created in the code as distributed. *
* This code will have to change only if you want to increase the maximum number of obstacles * allowed. *
* @param imageFileName The name of a .jpg file to use as the image for the obstacle. *
* @return A Player that has been assigned an initial, non-overlapping position and a velocity of zero. */ public Player createObstacle( String imageFileName ) { Player newObstacle = this.createPlayer( imageFileName, 0, 0 ); if ( firstObstacle == null ) { firstObstacle = newObstacle; } else if ( secondObstacle == null ) { secondObstacle = newObstacle; } else { mainWindow.print( "Full - Can't create new obstacle"); return null; } if ( newObstacle != null ) { newObstacle.addToWindow( mainWindow ); } return newObstacle; } /** * This is a private, helper method for creating both balls and obstacles. * It handles the things they have in common - checking to make sure the * image file exists, creating a new Player, setting its velocity, and * invoking pickPlayerPosition() to choose a location for it inside the * boundary rectangle that does not overlap any other players (balls or obstacles). *
* You should never need to change any code in this method. *
* @param imageFileName The name of a .jpg file to use as the image for the player. * @param xSpeed The initial distance to move in the x direction each "step" * @param ySpeed The initial distance to move in the y direction each "step" *
* @return The Player created, or null if the image file named doesn't exist. */ private Player createPlayer( String imageFileName, int xSpeed, int ySpeed ) { File imageFile = new File( imageFileName ); if ( !imageFile.exists() ) { mainWindow.print( "Image file " + imageFile.getAbsolutePath() + " does not exist" ); return null; } Image newImage = mainWindow.getImageFromFilename( imageFileName ); if ( newImage == null ) { mainWindow.print( "Failed to load image from file " + imageFile.getAbsolutePath() + "\nAre you sure it is an image file?" ); } Player newPlayer = new Player ( newImage ); newPlayer.setVelocity( xSpeed, ySpeed ); this.pickPlayerPosition( newPlayer ); return newPlayer; } /** * Pick a random position INSIDE the bounding rectangle that does not overlap any other players. *
* "random.nextInt(...)" returns a randomly chosen integer from 0 to the integer passed to it. *
* Don't worry about the "do {...} while(...)" -- we'll get to it next week. (Basically it lets us * keep picking new random positions until we find one that doesn't overlap anything.) *
* @param player The player (ball or obstacle) that we are trying to find a place for. */ private void pickPlayerPosition( Player player ) { Random random = new Random(); int xPosition = 0; int yPosition = 0; boolean doesIntersect = false; int numberOfTries = 0; if ( boundary.getWidth() < player.getWidth() || boundary.getHeight() < player.getHeight() ) { mainWindow.print( "Failure - Image is too big for this use" ); return; } do { xPosition = boundary.getX() + random.nextInt( boundary.getWidth() - player.getWidth() ); yPosition = boundary.getY() + random.nextInt( boundary.getHeight() - player.getHeight() ); player.setPosition( xPosition, yPosition ); doesIntersect = false; doesIntersect = doesIntersect | player.intersects( firstBall ); doesIntersect = doesIntersect | player.intersects( secondBall ); doesIntersect = doesIntersect | player.intersects( firstObstacle ); doesIntersect = doesIntersect | player.intersects( secondObstacle ); numberOfTries = numberOfTries + 1; } while ( doesIntersect && numberOfTries < 500 ); if ( numberOfTries >= 500 ) { mainWindow.print( "Warning: Couldn't find an open spot for this player" ); } } /** * Runs the simulation for a fixed number of steps. * Each ball in the simulation is moved by its x and y velocity distances. (I know - that's * confusing a rate and a distance. All the variables are actually distances to move, even * if their names have "velocity" in them.) *
* You should never have to change this routine, no matter what changes you're trying to make. *
* @param numSteps The number of simulation steps to run before returning.
*/
public void go( int numSteps ) {
int step;
// Well, once again, don't worry about the details of this code.
// For now, all that matters is that it causes the ball to be moved "numSteps" times.
// (The ugliness here is because of gymnastics required to get any semblance of a smooth
// smooth display of motion on the screen.)
for (step=0; step
* @param ball The Player in motion. May be null.
* @param obs The obstacle. May be null.
*/
private void bounceOffObstacle( Player ball, Player obs ) {
if ( ball != null && obs != null ) {
ball.bounceOffRectangle( obs.getBoundingBox() );
}
}
/**
* The ubiquitous helper function (to help with debugging, primarily.)
*/
public String toString() {
String result = "BallGame:\n";
if ( firstBall != null ) {
result = result + " First Ball: " + firstBall.toString() + "\n";
}
if ( secondBall != null ) {
result = result + " Second Ball: " + secondBall.toString() + "\n";
}
if ( firstObstacle != null ) {
result = result + " First Obstacle: " + firstObstacle.toString() + "\n";
}
if ( secondObstacle != null ) {
result = result + " Second Obstacle: " + secondObstacle.toString() + "\n";
}
return result;
}
}