Skip to content

Instantly share code, notes, and snippets.

@NatashaTheRobot
Created November 18, 2011 05:58
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save NatashaTheRobot/1375730 to your computer and use it in GitHub Desktop.
Save NatashaTheRobot/1375730 to your computer and use it in GitHub Desktop.
Stanford CS106A Breakout Game Solution
/*
* File: Breakout.java
* -------------------
* Name:
* Section Leader:
*
* This file will eventually implement the game of Breakout.
*/
import acm.graphics.*;
import acm.program.*;
import acm.util.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Breakout extends GraphicsProgram {
/** Width and height of application window in pixels */
public static final int APPLICATION_WIDTH = 400;
public static final int APPLICATION_HEIGHT = 600;
/** Dimensions of game board (usually the same) */
private static final int WIDTH = APPLICATION_WIDTH;
private static final int HEIGHT = APPLICATION_HEIGHT;
/** Dimensions of the paddle */
private static final int PADDLE_WIDTH = 60;
private static final int PADDLE_HEIGHT = 10;
/** Offset of the paddle up from the bottom */
private static final int PADDLE_Y_OFFSET = 30;
/** Number of bricks per row */
private static final int NBRICKS_PER_ROW = 10;
/** Number of rows of bricks */
private static final int NBRICK_ROWS = 10;
/** Separation between bricks */
private static final int BRICK_SEP = 4;
/** Width of a brick */
private static final int BRICK_WIDTH =
(WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;
/** Height of a brick */
private static final int BRICK_HEIGHT = 8;
/** Radius of the ball in pixels */
private static final int BALL_RADIUS = 10;
/** Offset of the top brick row from the top */
private static final int BRICK_Y_OFFSET = 70;
/** Number of turns */
private static final int NTURNS = 3;
/**Ball velocity*/
private double vx, vy;
/**Random number generator for vx*/
private RandomGenerator rgen = RandomGenerator.getInstance();
/** Animation delay or paust time between ball moves */
private static final int DELAY = 10;
/* Method: run() */
/** Runs the Breakout program. */
public void run() {
for(int i=0; i < NTURNS; i++) {
setUpGame();
playGame();
if(brickCounter == 0) {
ball.setVisible(false);
printWinner();
break;
}
if(brickCounter > 0) {
removeAll();
}
}
if(brickCounter > 0) {
printGameOver();
}
}
private void setUpGame() {
drawBricks( getWidth()/2, BRICK_Y_OFFSET);
drawPaddle();
drawBall();
}
//adding an individual brick object
private GRect brick;
//drawing all the bricks necessary for the game
private void drawBricks(double cx, double cy) {
/*need to have several columns in each row
* so there need to be two for loops,
* one for loop for the rows and one for loop for the columns.
*/
for( int row = 0; row < NBRICK_ROWS; row++ ) {
for (int column = 0; column < NBRICKS_PER_ROW; column++) {
/* To get the x coordinate for the starting width:
* start at the center width,
* subtract half of the bricks (width) in the row,
* subtract half of the separations (width) between the bricks in the row,
* now you're at where the first brick should be,
* so for the starting point of the next bricks in the column, you need to:
* add a brick width
* add a separation width
*/
double x = cx - (NBRICKS_PER_ROW*BRICK_WIDTH)/2 - ((NBRICKS_PER_ROW-1)*BRICK_SEP)/2 + column*BRICK_WIDTH + column*BRICK_SEP;
/* To get the y coordinate of the starting height:
* start at the given length from the top for the first row,
* then add a brick height and a brick separation for each of the following rows
*/
double y = cy + row*BRICK_HEIGHT + row*BRICK_SEP;
brick = new GRect( x , y , BRICK_WIDTH , BRICK_HEIGHT );
add (brick);
brick.setFilled(true);
//Setting colors depending on which row the bricks are in
if (row < 2) {
brick.setColor(Color.RED);
}
if (row == 2 || row == 3) {
brick.setColor(Color.ORANGE);
}
if (row == 4 || row == 5) {
brick.setColor(Color.YELLOW);
}
if (row == 6 || row == 7) {
brick.setColor(Color.GREEN);
}
if (row == 8 || row == 9) {
brick.setColor(Color.CYAN);
}
}
}
}
//adding individual paddle object
private GRect paddle;
//paddle set-up
private void drawPaddle() {
//starting the paddle in the middle of the screen
double x = getWidth()/2 - PADDLE_WIDTH/2;
//the paddle height stays consistent throughout the game
//need to make sure to subtract the PADDLE_HEIGHT,
//since the rectangle gets drawn from the top left corner
double y = getHeight() - PADDLE_Y_OFFSET - PADDLE_HEIGHT;
paddle = new GRect (x, y, PADDLE_WIDTH, PADDLE_HEIGHT);
paddle.setFilled(true);
add (paddle);
addMouseListeners();
}
//making the mouse track the paddle
public void mouseMoved(MouseEvent e) {
/* The mouse tracks the middle point of the paddle.
* If the middle point of the paddle is between half paddle width of the screen
* and half a paddle width before the end of the screen,
* the x location of the paddle is set at where the mouse is minus half a paddle's width,
* and the height remains the same
*/
if ((e.getX() < getWidth() - PADDLE_WIDTH/2) && (e.getX() > PADDLE_WIDTH/2)) {
paddle.setLocation(e.getX() - PADDLE_WIDTH/2, getHeight() - PADDLE_Y_OFFSET - PADDLE_HEIGHT);
}
}
//adding an individual ball object
private GOval ball;
//ball set-up
private void drawBall() {
double x = getWidth()/2 - BALL_RADIUS;
double y = getHeight()/2 - BALL_RADIUS;
ball = new GOval(x, y, BALL_RADIUS, BALL_RADIUS);
ball.setFilled(true);
add(ball);
}
private void playGame() {
waitForClick();
getBallVelocity();
while (true) {
moveBall();
if (ball.getY() >= getHeight()) {
break;
}
if(brickCounter == 0) {
break;
}
}
}
private void getBallVelocity() {
vy = 4.0;
vx = rgen.nextDouble(1.0, 3.0);
if (rgen.nextBoolean(0.5)) {
vx = -vx;
}
}
private void moveBall() {
ball.move(vx, vy);
//check for walls
//need to get vx and vy at the point closest to 0 or the other edge
if ((ball.getX() - vx <= 0 && vx < 0 )|| (ball.getX() + vx >= (getWidth() - BALL_RADIUS*2) && vx>0)) {
vx = -vx;
}
//We don't need to check for the bottom wall, since the ball can fall through the wall at that point
if ((ball.getY() - vy <= 0 && vy < 0 )) {
vy = -vy;
}
//check for other objects
GObject collider = getCollidingObject();
if (collider == paddle) {
/* We need to make sure that the ball only bounces off the top part of the paddle
* and also that it doesn't "stick" to it if different sides of the ball hit the paddle quickly and get the ball "stuck" on the paddle.
* I ran "println ("vx: " + vx + ", vy: " + vy + ", ballX: " + ball.getX() + ", ballY: " +ball.getY());"
* and found that the ball.getY() changes by 4 every time, instead of 1,
* so it never reaches exactly the the height at which the ball hits the paddle (paddle height + ball height),
* therefore, I estimate the point to be greater or equal to the height at which the ball hits the paddle,
* but less than the height where the ball hits the paddle minus 4.
*/
if(ball.getY() >= getHeight() - PADDLE_Y_OFFSET - PADDLE_HEIGHT - BALL_RADIUS*2 && ball.getY() < getHeight() - PADDLE_Y_OFFSET - PADDLE_HEIGHT - BALL_RADIUS*2 + 4) {
vy = -vy;
}
}
//since we lay down a row of bricks, the last brick in the brick wall is assigned the value brick.
//so we narrow it down by saying that the collier does not equal to a paddle or null,
//so all that is left is the brick
else if (collider != null) {
remove(collider);
brickCounter--;
vy = -vy;
}
pause (DELAY);
}
private GObject getCollidingObject() {
if((getElementAt(ball.getX(), ball.getY())) != null) {
return getElementAt(ball.getX(), ball.getY());
}
else if (getElementAt( (ball.getX() + BALL_RADIUS*2), ball.getY()) != null ){
return getElementAt(ball.getX() + BALL_RADIUS*2, ball.getY());
}
else if(getElementAt(ball.getX(), (ball.getY() + BALL_RADIUS*2)) != null ){
return getElementAt(ball.getX(), ball.getY() + BALL_RADIUS*2);
}
else if(getElementAt((ball.getX() + BALL_RADIUS*2), (ball.getY() + BALL_RADIUS*2)) != null ){
return getElementAt(ball.getX() + BALL_RADIUS*2, ball.getY() + BALL_RADIUS*2);
}
//need to return null if there are no objects present
else{
return null;
}
}
private void printGameOver() {
GLabel gameOver = new GLabel ("Game Over", getWidth()/2, getHeight()/2);
gameOver.move(-gameOver.getWidth()/2, -gameOver.getHeight());
gameOver.setColor(Color.RED);
add (gameOver);
}
private int brickCounter = 100;
private void printWinner() {
GLabel Winner = new GLabel ("Winner!!", getWidth()/2, getHeight()/2);
Winner.move(-Winner.getWidth()/2, -Winner.getHeight());
Winner.setColor(Color.RED);
add (Winner);
}
}
@Manisha4
Copy link

what does "ball" do? where have you defined that??

@mikeattey
Copy link

Th acm library Doesnt Exsist

@GregorBeuster
Copy link

Thanks for sharing... helped a lot!

@pandrey2003
Copy link

Do not forget to put brickCounter = 100; into the method setUpGame(). Otherwise, when you lose and before loss you've already removed, say, 5 balls, brickCounter will be equal to 100 - 5 = 95 at the next try which gives a bug!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment