From 3484e309668b974a045b7ef86ec45e6d966fe7f0 Mon Sep 17 00:00:00 2001
From: Muna Kandel <mkandel2@myune.edu.au>
Date: Thu, 21 Sep 2023 22:25:36 +0545
Subject: [PATCH] Closes #12 PowerUp implementation

---
 app/src/main/java/brickbreaker/App.java       |  4 +-
 app/src/main/java/brickbreaker/Ball.java      | 10 +--
 .../brickbreaker/GameComponents/Brick.java    | 38 ++++++++---
 .../GameComponents/DefaultBrickFactory.java   | 13 ++--
 .../java/brickbreaker/GameMapBuilder.java     | 58 +++++++---------
 app/src/main/java/brickbreaker/GamePanel.java | 66 +++++++++++--------
 .../brickbreaker/Interfaces/BrickFactory.java |  9 ---
 .../brickbreaker/Interfaces/GameObserver.java |  9 +--
 .../main/java/brickbreaker/LoginFrame.java    |  4 --
 app/src/main/java/brickbreaker/Vector.java    |  9 +--
 10 files changed, 101 insertions(+), 119 deletions(-)

diff --git a/app/src/main/java/brickbreaker/App.java b/app/src/main/java/brickbreaker/App.java
index a18c0a5..6282541 100644
--- a/app/src/main/java/brickbreaker/App.java
+++ b/app/src/main/java/brickbreaker/App.java
@@ -1,6 +1,4 @@
-/*
- * This Java source file was generated by the Gradle 'init' task.
- */
+
 package brickbreaker;
 
 import javax.swing.JFrame;
diff --git a/app/src/main/java/brickbreaker/Ball.java b/app/src/main/java/brickbreaker/Ball.java
index 3cc1a80..ca11a7d 100644
--- a/app/src/main/java/brickbreaker/Ball.java
+++ b/app/src/main/java/brickbreaker/Ball.java
@@ -1,23 +1,15 @@
-/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
- */
 package brickbreaker;
 
 import java.awt.Color;
 import java.awt.Graphics;
 
-/**
- *
- * @author Suman
- */
 public class Ball {
     private Vector position;
     private Vector direction;
     public int radius;
     public Color color;
     
-    public Ball(int posX, int posY, int dirX, int dirY, int radius,Color color) {
+    public Ball(int posX, int posY, int dirX, int dirY, int radius, Color color) {
         this.position = new Vector(posX, posY);
         this.direction = new Vector(dirX, dirY);
         this.radius = radius;
diff --git a/app/src/main/java/brickbreaker/GameComponents/Brick.java b/app/src/main/java/brickbreaker/GameComponents/Brick.java
index 5c03328..f03fe10 100644
--- a/app/src/main/java/brickbreaker/GameComponents/Brick.java
+++ b/app/src/main/java/brickbreaker/GameComponents/Brick.java
@@ -1,23 +1,18 @@
-/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
- */
+
 package brickbreaker.GameComponents;
 
 import brickbreaker.Vector;
 import java.awt.Color;
 import java.awt.Graphics2D;
 
-/**
- *
- * @author Suman
- */
 public class Brick {
     private Vector position;
     private int width;
     private int height;
     private Color color;
-    private Boolean hasPowerUp;
+    public Boolean hasPowerUp;
+    private final int value = 5;
+    private boolean isHit = false;
 
     public Brick(int x, int y, int width, int height, Color color, Boolean hasPowerUp) {
         this.position = new Vector(x, y);
@@ -34,4 +29,29 @@ public class Brick {
         g.setColor(Color.BLACK);
         g.drawRect(this.position.x, this.position.y, width, height);
     }
+    
+    public void setIsHit(boolean isHit) {
+        this.isHit = isHit;
+    }
+    
+    public boolean getIsHit() {
+        return isHit;
+    }
+    
+    
+    public int getValue() {
+        return value;
+    }
+    
+    public Vector getPosition() {
+        return position;
+    }
+    
+    public int getHeight() {
+        return height;
+    }
+    
+    public int getWidth() {
+        return width;
+    }
 }
diff --git a/app/src/main/java/brickbreaker/GameComponents/DefaultBrickFactory.java b/app/src/main/java/brickbreaker/GameComponents/DefaultBrickFactory.java
index a086497..d8f5d83 100644
--- a/app/src/main/java/brickbreaker/GameComponents/DefaultBrickFactory.java
+++ b/app/src/main/java/brickbreaker/GameComponents/DefaultBrickFactory.java
@@ -1,21 +1,16 @@
-/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
- */
+
 package brickbreaker.GameComponents;
 
 import brickbreaker.GameComponents.Brick;
 import brickbreaker.Interfaces.BrickFactory;
 import java.awt.Color;
 
-/**
- *
- * @author Suman
- */
 public class DefaultBrickFactory implements BrickFactory {
     @Override
     public Brick createBrick(int x, int y, int width, int height, Boolean hasPowerUp) {
-        Color color = Color.decode("#FF0000");
+        Color color = Color.decode("#BC4A3C");
+        if(hasPowerUp)
+            color = Color.decode("#FF0000");
         return new Brick(x, y, width, height, color, hasPowerUp);
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/brickbreaker/GameMapBuilder.java b/app/src/main/java/brickbreaker/GameMapBuilder.java
index 3b6562e..8d59cc6 100644
--- a/app/src/main/java/brickbreaker/GameMapBuilder.java
+++ b/app/src/main/java/brickbreaker/GameMapBuilder.java
@@ -1,62 +1,52 @@
-/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
- */
+
 package brickbreaker;
 
 import brickbreaker.GameComponents.Brick;
 import brickbreaker.Interfaces.BrickFactory;
-import java.awt.BasicStroke;
-import java.awt.Color;
 import java.awt.Graphics2D;
 
-/**
- *
- * @author Suman
- */
 public class GameMapBuilder {
 	
-	public int map [][];
-	public int brickWidth;
-	public int brickHeight;
+	public Brick map [][];
+	public int brickWidth = 50;
+	public int brickHeight = 20;
 	private BrickFactory brickfactory;
-        private final int maxNoOfPowerUps = 5;
-	// this creates the brick of size 4x8
+        private final int maxNoOfPowerUpsPerRow = 5;
+        
 	public GameMapBuilder(int row, int col, BrickFactory brickFactory) {
-            map = new int [row][col];
+            map = new Brick [row][col];
+            this.brickfactory = brickFactory;
+
             for (int i = 0; i < map.length; i++) { 
+                int numberOfPowerUps = (int) (Math.random() * maxNoOfPowerUpsPerRow );
                 for (int j=0; j< map[0].length;j++) {
-                    map[i][j] = 1;
+             
+                    boolean hasPowerUp = false;
+                    if(numberOfPowerUps > 0) {
+                        hasPowerUp = Math.random() < 0.5;
+                    }
+                    if(hasPowerUp) {
+                        numberOfPowerUps--;
+                    }
+                    Brick brick = brickfactory.createBrick(j*brickWidth, i*brickHeight, brickWidth, brickHeight, hasPowerUp);
+                    
+                    map[i][j] = brick;
                 }
             }
-            brickWidth = 50;
-            brickHeight = 20;
-            this.brickfactory = brickFactory;
+            
 	}
 	
 	// this draws the bricks
 	public void draw(Graphics2D g) {
             
-            int numberOfPowerUps = (int) (Math.random() * maxNoOfPowerUps );
             for (int i = 0; i < map.length; i++) {
                 for (int j=0; j< map[0].length;j++) {
-                    if(map[i][j] > 0) {
-                      
-                        boolean hasPowerUp = false;
-                        if(numberOfPowerUps > 0) {
-                            hasPowerUp = Math.random() < 0.5;
-                        }
-                        if(hasPowerUp) numberOfPowerUps--;
-                        Brick brick = brickfactory.createBrick(j*brickWidth, i*brickHeight, brickWidth, brickHeight, hasPowerUp);
+                    Brick brick = map[i][j];
+                    if(!brick.getIsHit()) {
                         brick.draw(g);
                     }
                 }
             }
 	}
-	
-	// this sets the value of brick to 0 if it is hit by the ball
-	public void setBrickValue(int value, int row, int col) {
-            map[row][col] = value;
-	}
 
 }
\ No newline at end of file
diff --git a/app/src/main/java/brickbreaker/GamePanel.java b/app/src/main/java/brickbreaker/GamePanel.java
index 9dc12ee..d9dfc07 100644
--- a/app/src/main/java/brickbreaker/GamePanel.java
+++ b/app/src/main/java/brickbreaker/GamePanel.java
@@ -1,5 +1,6 @@
 package brickbreaker;
 
+import brickbreaker.GameComponents.Brick;
 import brickbreaker.Interfaces.BrickFactory;
 import brickbreaker.Interfaces.GameObserver;
 import brickbreaker.GameComponents.DefaultBrickFactory;
@@ -26,21 +27,18 @@ public class GamePanel extends JPanel implements KeyListener, ActionListener {
 
     private int paddle = 310;
 
-    private List<Ball> balls = new ArrayList<>(); // Use List interface instead of ArrayList
-
+    private List<Ball> balls = new ArrayList<>();
     private String font = "MV Boli";
 
-    private GameMapBuilder map;
+    private GameMapBuilder gameMap;
 
     public GamePanel() {
         Color color = Color.decode("#8B4513");
-        this.balls.add(new Ball(350, 450, 2, -2, 20, color)); // Adjust the initial ball position and direction
-        color = Color.decode("#008080");
-        this.balls.add(new Ball(380, 420, -2, 2, 50, color));
+        this.balls.add(new Ball(350, 450, 2, -2, 20, color));
         this.totalBricks = rows * columns;
 
         BrickFactory brickfactory = new DefaultBrickFactory();
-        map = new GameMapBuilder(rows, columns, brickfactory);
+        gameMap = new GameMapBuilder(rows, columns, brickfactory);
         addKeyListener(this);
         setFocusable(true);
         setFocusTraversalKeysEnabled(false);
@@ -67,7 +65,7 @@ public class GamePanel extends JPanel implements KeyListener, ActionListener {
         graphics.setColor(Color.green);
         graphics.fillRect(1, 1, 692, 592);
 
-        map.draw((Graphics2D) graphics);
+        gameMap.draw((Graphics2D) graphics);
 
 
         graphics.setColor(Color.blue);
@@ -117,7 +115,10 @@ public class GamePanel extends JPanel implements KeyListener, ActionListener {
     @Override
     public void actionPerformed(ActionEvent arg0) {
         if (play) {
-            for (Ball ball : balls) {
+            Iterator<Ball> iterator = balls.iterator();
+            List<Ball> newBallsToAdd = new ArrayList<>();
+            while (iterator.hasNext()) {
+                Ball ball = iterator.next();
                 Vector ballPosition = ball.getPosition();
                 Vector ballDirection = ball.getDirection();
 
@@ -126,23 +127,34 @@ public class GamePanel extends JPanel implements KeyListener, ActionListener {
                     ball.setDirection(ballDirection.x, ballDirection.y);
                 }
 
-                for (int i = 0; i < map.map.length; i++) {
-                    for (int j = 0; j < map.map[0].length; j++) {
-                        if (map.map[i][j] > 0) {
-                            int brickX = j * map.brickWidth;
-                            int brickY = i * map.brickHeight;
-                            int brickWidth = map.brickWidth;
-                            int brickHeight = map.brickHeight;
-
-                            Rectangle brickRect = new Rectangle(brickX, brickY, brickWidth, brickHeight);
-                            Rectangle ballRect = new Rectangle(ballPosition.x, ballPosition.y, ball.radius, ball.radius);
-                            
+                for (int i = 0; i < gameMap.map.length; i++) {
+                    for (int j = 0; j < gameMap.map[0].length; j++) {
+                        Brick brick = gameMap.map[i][j];
+                        if (!brick.getIsHit()) {
+                            Vector brickPosition = brick.getPosition();
                             
+                            Rectangle brickRect = new Rectangle(brickPosition.x, brickPosition.y, brick.getWidth(), brick.getHeight());
+                            Rectangle ballRect = new Rectangle(ballPosition.x, ballPosition.y, ball.radius, ball.radius);
+
                             if (ballRect.intersects(brickRect)) {
-                                map.setBrickValue(0, i, j);
+                                brick.setIsHit(true);
                                 totalBricks--;
-                                score += 5;
-
+                                score += brick.getValue();
+                                
+                                if(brick.hasPowerUp) {
+                                    int noOfBallsToSpawn = (int) (Math.random() * 5);
+                                    System.out.println(noOfBallsToSpawn);
+                                    for (int k=0; k<noOfBallsToSpawn; k++) {
+                                        boolean positiveXDirection = Math.random() > 0.5;
+                                        boolean positiveYDirection = Math.random() > 0.5;
+                                        int dirX = (positiveXDirection)? 1: -1;
+                                        int dirY = (positiveYDirection)? 1: -1;
+                                        Color color = Color.GRAY;
+                                        Ball newBall = new Ball(brickPosition.x, brickPosition.y, dirX, dirY, ball.radius, color);
+                                        newBallsToAdd.add(newBall);
+                                    }
+                                }
+                                
                                 if (ballPosition.x + 19 <= brickRect.x || ballPosition.x + 1 >= brickRect.x + brickRect.width) {
                                     ballDirection.x = -ballDirection.x;
                                 } else {
@@ -153,8 +165,9 @@ public class GamePanel extends JPanel implements KeyListener, ActionListener {
                     }
                 }
                 ball.setDirection(ballDirection.x, ballDirection.y);
-                ball.move(); // Call the move() method to update the ball's position
+                ball.move();
             }
+            balls.addAll(newBallsToAdd);
         }
 
         repaint();
@@ -185,11 +198,12 @@ public class GamePanel extends JPanel implements KeyListener, ActionListener {
             if (!play) {
                 play = true;
                 Color color = Color.decode("#8B4513");
-                this.balls.add(new Ball(350, 450, 1, -1, 20, color)); // Adjust the initial ball position and direction
+                this.balls.clear();
+                this.balls.add(new Ball(350, 450, 2, -2, 20, color)); 
                 score = 0;
                 totalBricks = rows * columns;
                 BrickFactory brickfactory = new DefaultBrickFactory();
-                map = new GameMapBuilder(rows, columns, brickfactory);
+                gameMap = new GameMapBuilder(rows, columns, brickfactory);
 
                 repaint();
             }
diff --git a/app/src/main/java/brickbreaker/Interfaces/BrickFactory.java b/app/src/main/java/brickbreaker/Interfaces/BrickFactory.java
index ba3cedf..bffec1d 100644
--- a/app/src/main/java/brickbreaker/Interfaces/BrickFactory.java
+++ b/app/src/main/java/brickbreaker/Interfaces/BrickFactory.java
@@ -1,16 +1,7 @@
-/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
- */
 package brickbreaker.Interfaces;
 
 import brickbreaker.GameComponents.Brick;
-import java.awt.Color;
 
-/**
- *
- * @author Suman
- */
 public interface BrickFactory {
     Brick createBrick(int x, int y, int width, int height, Boolean hasPowerup);
 }
diff --git a/app/src/main/java/brickbreaker/Interfaces/GameObserver.java b/app/src/main/java/brickbreaker/Interfaces/GameObserver.java
index e30d97e..6e16d2f 100644
--- a/app/src/main/java/brickbreaker/Interfaces/GameObserver.java
+++ b/app/src/main/java/brickbreaker/Interfaces/GameObserver.java
@@ -1,13 +1,6 @@
-/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
- */
+
 package brickbreaker.Interfaces;
 
-/**
- *
- * @author Suman
- */
 public interface GameObserver {
     void onGameOver(int finalScore);
     void onGameWin(int finalScore);
diff --git a/app/src/main/java/brickbreaker/LoginFrame.java b/app/src/main/java/brickbreaker/LoginFrame.java
index 4dd910a..23414da 100644
--- a/app/src/main/java/brickbreaker/LoginFrame.java
+++ b/app/src/main/java/brickbreaker/LoginFrame.java
@@ -1,9 +1,5 @@
 package brickbreaker;
 
-/**
- *
- * @author Suman
- */
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.ActionEvent;
diff --git a/app/src/main/java/brickbreaker/Vector.java b/app/src/main/java/brickbreaker/Vector.java
index 258cb98..bf8bcda 100644
--- a/app/src/main/java/brickbreaker/Vector.java
+++ b/app/src/main/java/brickbreaker/Vector.java
@@ -1,13 +1,6 @@
-/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
- */
+
 package brickbreaker;
 
-/**
- *
- * @author Suman
- */
 public class Vector {
     public int x;
     public int y;
-- 
GitLab