BreakOut Game

Breakout is a game in which you as a player control a bat which is at the bottom of the game panel which is used to prevent the ball to escape from the bottom of the game panel. This game will not end until you break all the bricks present in the game panel. And these bricks will be destroyed by making the ball to collide with them. You will get three lives to do so.

Explaining the code:-

Let's start with creating a new project in Eclipse IDE name BreakOut.In this project, I have used three classes. One which controls the main frame and another which is used to join the scoreboard panel and main panel in which the game is played and lastly there is the brick class which is used to make all the bricks present in the main panel. Let's discuss these classes and methods present in it one by one.

Brick Class

Firstly, let's study the Brick class in which variables are declared to define a brick such as
int brickxpos,brickypos;
int brickwidth=100,brickheight=50;

int xoffset=140;
int yoffset=50;

int xgap=20;
int ygap=20;
These variables itself describe what they are made for. The constructor of this class initializes the position of the brick.
public Brick(int i,int j){
  brickxpos=xoffset+brickwidth*j+xgap*j;
  brickypos=yoffset+brickheight*i+ygap*i;
}
There is only one method in this class which is used to draw the bricks on the main panel.
public void drawBrick(Graphics g){
  g.fill3DRect(brickxpos, brickypos, brickwidth, brickheight, true);
  g.setColor(Color.white);
  g.drawRect(brickxpos, brickypos, brickwidth, brickheight);
}
BreakOut welcome

GamePanel Class

Now, see the GamePanel class which is used to put together two classes, ScoreBoard class where the score and lives left is updated and MainPanel class where the whole game is played. Let's take up ScoreBoard class first which is used to update the score and lives. Also, it draws the score, lives, and title of the game i.e BreakOut on the ScoreBoard panel.
 public class ScoreBoard extends JPanel{
  int score=0;
  int life =3;
  
  public ScoreBoard(){
    this.setPreferredSize(new Dimension(width,180));
    this.setBorder(BorderFactory.createLineBorder(Color.CYAN, 3));
    this.setBackground(Color.blue);
  }
  
  public void paintComponent(Graphics g){
    super.paintComponent(g);
    g.setColor(Color.WHITE);
    g.setFont(new Font("Times new roman",Font.PLAIN,100));
    g.drawString("BreakOut", 430, 120);
    
    g.setFont(new Font("Times new roman",Font.PLAIN,50));
    g.drawString("Score: "+score, 1000, 140);
    g.drawString("Life: "+life, 20, 140);
  }
  
  void refresh(){
    repaint();
  }
}
scoreboard

GamePanel Class

Now, let's discuss the biggest class in this project which handles most of the game. This class has many variables and methods. These are the variables declared in this class.
Timer t;

int width=1220,height=780;

//bat
int batxpos=500,batypos=740;
int batxvel=0;
int batwidth=130,batheight=15;

//ball

int balldia=30;
int ballxpos= (batxpos+(int)(batwidth/2) - (balldia/2)),ballypos=batypos-balldia-3;
int ballxvel=0,ballyvel=0;


//bricks
int rows=4,cols=8;
Brick b[][] =  new Brick[rows][cols];
int brickvalue[][] = new int[rows][cols];
int bricksleft=rows*cols;

//game variables
boolean gameover=false;
boolean startgame=false;
boolean winner=false;

boolean batcollide=false;
And the constructor of the class, which is used to initialize the variables and also the main panel.
public MainPanel(){
  this.setPreferredSize(new Dimension(width,height));
  this.setBorder(BorderFactory.createLineBorder(Color.GRAY, 3));
  this.setBackground(Color.cyan);
  t = new Timer(1,this);
  setValue();
  addKeyListener(this);
  setFocusable(true);
  this.setFocusTraversalKeysEnabled(false);
  
  t.start();
}
Let's see the paintComponent() method, which is used to draw the main panel with the bricks, balls, bat and some strings.
public void paintComponent(Graphics g){
  super.paintComponent(g);
  
  drawBrickMap(g);
  
  g.setColor(Color.gray);
  g.fill3DRect(batxpos, batypos, batwidth, batheight, true);
  g.setColor(Color.BLACK);
  g.drawRect(batxpos, batypos, batwidth, batheight);
  
  
  
  g.setColor(Color.BLUE);
  g.fillOval(ballxpos, ballypos, balldia, balldia);
  
  
  if(!startgame && !gameover){
    drawStartGame(g);
  }
  
  if(winner){
    drawOptions(g);
    win(g);
    t.stop();
  }
  
  if(gameover){
  drawOptions(g);
  showGameover(g);
  }
  
  
}
gamepanel Here, we have many methods which do as their name suggests such showGameover() will print the message at the time when the player loses. Let's see these methods more closely.
public void drawBrickMap(Graphics g){
  for(int i=0;i<rows;i++){
    for(int j=0;j<cols;j++){
      if(brickvalue[i][j] == 1){
      switch((int)i%2){
      case 0: g.setColor(Color.orange);
      break;
      case 1: g.setColor(Color.GREEN);
      break;
      }
      b[i][j].drawBrick(g);
      }
    }
  }
}
This method is used to draw all the bricks on the main panel. Now the methods which print the message at the time of win or loose or getting out or starting the game.
void showGameover(Graphics g){
  
  g.setColor(Color.orange);
  g.setFont(new Font("Times new roman",Font.PLAIN,48));
  g.drawString("GAME OVER", width/2-170, height/2 + 10);
  g.setColor(Color.GREEN);
  g.setFont(new Font("Times new roman",Font.BOLD,48));
  g.drawString("SCORE : "+ s.score, width/2-150, height/2 + 60);
  
}

void win(Graphics g){
  
    g.setColor(Color.ORANGE);
    g.setFont(new Font("Times new roman",Font.ITALIC,40));
    g.drawString("You Have Cleared The Game.", width/2-260, height/2 - 120);
    g.setColor(Color.GREEN);
    g.setFont(new Font("Times new roman",Font.BOLD,48));
    g.drawString("SCORE : "+ s.score, width/2-150, height/2 - 70);
  
}

public void drawOptions(Graphics g){
  g.setColor(Color.orange);
  g.setFont(new Font("Times new roman",Font.ITALIC,42));
  g.drawString("Press [ESC] to exit the game", width/2-260, height/2 + 120);
  g.drawString("Press [R] to restart the game", width/2-260, height/2 + 170);
}

public void drawStartGame(Graphics g){
  g.setColor(Color.blue);
  g.setFont(new Font("Times new roman",Font.ITALIC,42));
  g.drawString("Press [SPACE] to start the game", width/2-280, height/2 + 30);
}
intermediate In this class, I have used the timer to animate the movement of the ball and also the bat. This class implements the ActionListener and KeyListener interface. This ActionListener helps to make an actionPerformed() method which is executed after every millisecond, the time defined in the Timer class variable.
Timer t = new Timer(1,this);
Here, this keyword specifies that MainPanel is the action listener for timer events. And hence calls the actionPerformed() method. In actionPerformed() method it updates the position of ball and bat every millisecond.
ballxpos += ballxvel;
ballypos += ballyvel;

batxpos+=batxvel;
It ensures that the bat and the ball remain in the main panel and also if the ball escapes from the bottom then call appropriate methods and also update the variables.
if(batxpos < 0 || batxpos+batwidth > width){
  batxvel =0;
}

if(ballxpos < 0 || ballxpos+balldia >= width){
  ballxvel = -ballxvel;
}
if(ballypos < 0){
  ballyvel = -ballyvel;
}
if(ballypos >=  height){

  s.life--;
  if(s.life ==0){
  gameover=true;
  startgame=false;
  t.stop();
  }else{
    batxpos=500;	batypos=740;
    ballxpos= (batxpos+(int)(batwidth/2) - (balldia/2));
    ballypos=batypos-balldia-3;
    ballxvel=0;ballyvel=0;
    startgame=false;
  }
  
  
}
It also checks how the ball interacting with the bat.
Ellipse2D.Double ball = new Ellipse2D.Double(ballxpos, ballypos, balldia, balldia);
Rectangle2D.Double bat=new Rectangle2D.Double(batxpos,batypos,batwidth,batheight);


if(!batcollide){
if(((ballypos+balldia) == batypos) &&
    (ballxpos+(balldia/2)) >= batxpos &&
    ((ballxpos+(balldia/2)) <= (batxpos+batwidth))){
    System.out.println("bat verticel");
    ballyvel = -ballyvel;
    batcollide = true;
  }else{
    if(ball.intersects(bat)){
      if(ballxpos < (batxpos+batwidth/2) && ballypos < (batypos+batheight)){
        
        if(ballxvel < 0 && ballyvel > 0){
          ballyvel = -ballyvel;
          System.out.println("bat vertical");
          
        }else
        if(ballxvel > 0 && ballyvel > 0){
          ballyvel = -ballyvel;
          ballxvel = -ballxvel;
          System.out.println("bat diagonal");
          
        }
      }else
      if(ballxpos > (batxpos+batwidth/2) && ballypos < (batypos+batheight)){
        if(ballxvel < 0 && ballyvel > 0){
          ballyvel = -ballyvel;
          ballxvel = -ballxvel;
          System.out.println("bat diagonal");
          
        }else
        if(ballxvel > 0 && ballyvel > 0){
          ballyvel = -ballyvel;
          System.out.println("bat vertical");
          
        }
      }
    batcollide = true;
    }
  }
}

if(batcollide){
  if(!ball.intersects(bat)){
    batcollide=false;
  }
}
And also checks between the ball and the individual brick.
A:		for(int i=0;i<rows;i++){
      for(int j=0;j<cols;j++){
        if(brickvalue[i][j] == 1){
      Rectangle2D.Double br = new Rectangle2D.Double(b[i][j].brickxpos, b[i][j].brickypos, b[i][j].brickwidth, b[i][j].brickheight);
      
        if(((ballypos+balldia) == b[i][j].brickypos) &&
            (ballxpos+(balldia/2)) >= b[i][j].brickxpos &&
            ((ballxpos+(balldia/2)) <= (b[i][j].brickxpos+b[i][j].brickwidth))){
            System.out.println("pure vertical");
            ballyvel = -ballyvel;
            update(i,j);
            break A;
            
          }else
          if((((ballypos) == (b[i][j].brickypos+b[i][j].brickheight)) &&
            (ballxpos+(balldia/2)) >= b[i][j].brickxpos) &&
            ((ballxpos+(balldia/2)) <= (b[i][j].brickxpos+b[i][j].brickwidth))){
            System.out.println("pure vertical");
            ballyvel = -ballyvel;
            update(i,j);
            break A;
          }else
          if(((ballxpos+balldia) == b[i][j].brickxpos) && 
            ((ballypos+(balldia/2)) >= b[i][j].brickypos) &&
            ((ballypos+(balldia/2)) <= (b[i][j].brickypos+b[i][j].brickheight))){
            System.out.println("pure horizontal");
            ballxvel = -ballxvel;
            update(i,j);
            break A;
          }else
          if(((ballxpos) == (b[i][j].brickxpos+b[i][j].brickwidth))&&
            ((ballypos+(balldia/2)) >= b[i][j].brickypos) &&
            ((ballypos+(balldia/2)) <= (b[i][j].brickypos+b[i][j].brickheight))){
            System.out.println("pure horizontal");
            ballxvel = -ballxvel;
            update(i,j);
            break A;
          }else
            if(ball.intersects(br)){
            if(ballxpos < (b[i][j].brickxpos+b[i][j].brickwidth/2) && ballypos < (b[i][j].brickypos+b[i][j].brickheight/2)){
              if(ballxvel > 0 && ballyvel < 0){
                System.out.println("horizontal");
                ballxvel = -ballxvel;
                update(i,j);
                break A;
              }else
              if(ballxvel < 0 && ballyvel > 0){
                ballyvel = -ballyvel;
                System.out.println("vertical");
                update(i,j);
                break A;
              }else
              if(ballxvel > 0 && ballyvel > 0){
                ballyvel = -ballyvel;
                ballxvel = -ballxvel;
                System.out.println("diagonal");
                update(i,j);
                break A;
              }
            }else
            if(ballxpos > (b[i][j].brickxpos+b[i][j].brickwidth/2) && ballypos < (b[i][j].brickypos+b[i][j].brickheight/2)){
              if(ballxvel < 0 && ballyvel > 0){
                ballyvel = -ballyvel;
                ballxvel = -ballxvel;
                System.out.println("diagonal");
                update(i,j);
                break A;
              }else
              if(ballxvel > 0 && ballyvel > 0){
                ballyvel = -ballyvel;
                System.out.println("vertical");
                update(i,j);
                break A;
              }else
              if(ballxvel < 0 && ballyvel < 0){
                System.out.println("horizontal");
                ballxvel = -ballxvel;
                update(i,j);
                break A;
              }
            }else
            if(ballxpos > (b[i][j].brickxpos+b[i][j].brickwidth/2) && ballypos > (b[i][j].brickypos+b[i][j].brickheight/2)){
              if(ballxvel > 0 && ballyvel < 0){
                System.out.println("vertical");
                ballyvel = -ballyvel;
                update(i,j);
                break A;
              }else
              if(ballxvel < 0 && ballyvel > 0){
                ballxvel = -ballxvel;
                System.out.println("horizontal");
                update(i,j);
                break A;
              }else
              if(ballxvel < 0 && ballyvel < 0){
                ballyvel = -ballyvel;
                ballxvel = -ballxvel;
                System.out.println("diagonal");
                update(i,j);
                break A;
              }
            }else
            if(ballxpos < (b[i][j].brickxpos+b[i][j].brickwidth/2) && ballypos > (b[i][j].brickypos+b[i][j].brickheight/2)){
              if(ballxvel > 0 && ballyvel < 0){
                ballyvel = -ballyvel;
                ballxvel = -ballxvel;
                System.out.println("diagonal");
                update(i,j);
                break A;
              }else
              if(ballxvel > 0 && ballyvel > 0){
                ballxvel = -ballxvel;
                System.out.println("horizontal");
                update(i,j);
                break A;
              }else
              if(ballxvel < 0 && ballyvel < 0){
                System.out.println("vertical");
                ballyvel = -ballyvel;
                update(i,j);
                break A;
              }
            }
          }
      }
    }
It also checks if bricks are left any more.
if(bricksleft <= 0){
  winner=true;
  t.stop();
}
Lastly repaints the main panel and also scoreboard panel.
repaint();
s.refresh();
That was all about the actionPerformed() method. life lost Now let's discuss the keyPressed() method and keyReleased() method. In keyPressed() method, the code executed according to the type of key is pressed.
public void keyPressed(KeyEvent e) {
  int key=e.getKeyCode();
  if(!startgame && !gameover){
  if(key == KeyEvent.VK_SPACE){
    startgame=true;
    ballxvel=1;ballyvel=1;
    t.start();
  }
  }
  if(!startgame){
  if(key==KeyEvent.VK_LEFT){
    if(batxpos >= 0 ){
    batxvel=-1;
    ballxvel=-1;
    }else{
      batxvel=0;
      ballxvel=0;
    }
  }
  if(key == KeyEvent.VK_RIGHT){
    if(batxpos+batwidth <= width){
    batxvel=1;
    ballxvel = 1;
    }else{
      batxvel=0;
      ballxvel=0;
    }
  }
  }
  
  if(startgame){
    if(key==KeyEvent.VK_LEFT){
      if(batxpos >= 0 ){
      batxvel=-1;
      
      }else
        batxvel=0;
    }
    if(key == KeyEvent.VK_RIGHT){
      if(batxpos+batwidth <= width){
      batxvel=1;
      
      }else
        batxvel=0;
    }
  }
  
  if(key == KeyEvent.VK_ESCAPE){
    System.exit(0);
  }
  
  if(key == KeyEvent.VK_R){
  
    batxpos=500;	batypos=740;
  
    
    
    ballxpos= (batxpos+(int)(batwidth/2) - (balldia/2));
    ballypos=batypos-balldia-3;
    ballxvel=0;		ballyvel=0;
    
    bricksleft=rows*cols;
    
    gameover=false;
    startgame=false;
    winner=false;
    setValue();
    s.life=3;
    s.score=0;
    s.refresh();
    t.start();
  }
  
  repaint();
  
  
}
And the keyReleased() method.
public void keyReleased(KeyEvent arg0) {
  if(!startgame){
    batxvel=0;
    ballxvel=0;
    }else
      batxvel=0;
  
}
That was all about the GamePanel class and its inner classes, ScoreBoard class and MainPanel class.

BreakOut Class

Now, let's see the main class i.e BreakOut class. In this class, we just include the panel of GamePanel class into the main Frame. And also add the visual description of the frame. gameover

BreakOut.java

public class BreakOut extends JFrame {
  public BreakOut(){
    super("BreakOut");
  }

  public static void main(String[] args) {
    BreakOut game = new BreakOut();
    Container c = game.getContentPane();
    c.setLayout(new FlowLayout(FlowLayout.CENTER));
    GamePanel p = new GamePanel();
    c.add(p);
    game.pack();
    game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    c.setBackground(Color.orange);
    game.setResizable(false);
    game.setLocationRelativeTo(null);
    game.setVisible(true);
    

  }
winner

To download the project content and source code. Click Here

The following two tabs change content below.
Amit Rawat

Amit Rawat

Founder and Developer at SpiderLabWeb
I love to work on new projects and also work on my ideas. My main field of interest is Web Development.

You may also like...