BreakOut Game
by Amit Rawat · Published · Updated
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.
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.
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.
Now let's discuss the keyPressed() method and keyReleased() method. In keyPressed() method, the code executed according to the type of key is pressed.
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 asint 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); }

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(); } }

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); } }

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); }

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.

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.
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); }

To download the project content and source code. Click Here
The following two tabs change content below.
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.
Latest posts by Amit Rawat (see all)
- Python Program to Print the Fibonacci Sequence (2 ways) - April 7, 2020
- Python Program to Display or Print Prime Numbers Between a Range or an Interval - June 18, 2019
- Python Program To Print Pascal’s Triangle (2 Ways) - June 17, 2019