I'm new to java and I have just finished my very first game - Arkanoid. I would appreciate, if anyone could look at this and tell me some advice and tips how can I optimize my code. Thank you. :)
I have 5 classes - Breaker, BlockBreakerPanel, Ball, Paddle, Block. Look:
This is the main classs:
public class Breaker {
private BlockBreakerPanel panel;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Breaker b = new Breaker();
b.show();
}
private void show() {
JFrame frame = new JFrame("Block Breaker");
frame.setSize(490, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.panel = new BlockBreakerPanel(this);
frame.add(this.panel);
frame.setVisible(true);
}
public BlockBreakerPanel getPanel() {
return this.panel;
}
}
class BlockBreakerPanel extends JPanel implements KeyListener, ActionListener
{
private ArrayList<Blocks> blocks = new ArrayList<>();
private final Paddle player;
private final Ball ball;
private final Breaker game;
private boolean gameOver;
private int score;
private boolean start;
public BlockBreakerPanel(Breaker game) {
setBackground(Color.BLACK);
for (int j = 0; j < 3; j++) {
for (int i = 0; i < 8; i++) {
this.blocks.add(new Blocks(i * 60 + 2, j * 40 + 5, 50, 30));
}
}
this.player = new Paddle(game);
this.ball = new Ball(game);
this.gameOver = false;
this.score = 0;
this.start = false;
Timer t = new Timer(5, this);
t.start();
addKeyListener(this);
setFocusable(true);
this.game = game;
}
public void addPoint() {
this.score++;
}
public void isGameOver() {
this.gameOver = true;
}
public ArrayList<Blocks> getBlocks() {
return this.blocks;
}
public Paddle getPlayer() {
return this.player;
}
public void paint(Graphics g) {
super.paintComponent(g);
this.blocks.forEach((block) -> {
block.paint(g);
});
this.player.paint(g);
this.ball.paint(g);
if (!this.start) {
g.setFont(new Font("Calibri", Font.BOLD, 35));
g.setColor(Color.WHITE);
g.drawString("Pressed enter to start a game", 20, 300);
}
g.setFont(new Font("Calibri", Font.BOLD, 20));
g.setColor(Color.WHITE);
g.drawString(String.valueOf(this.score), 450, 540);
if (this.gameOver) {
g.setFont(new Font("Calibri", Font.BOLD, 80));
g.setColor(Color.WHITE);
g.drawString("Game Over", 60, 300);
} else if (this.blocks.isEmpty()) {
this.gameOver = true;
g.setFont(new Font("Calibri", Font.BOLD, 80));
g.setColor(Color.WHITE);
g.drawString("You won", 80, 300);
}
}
private void update() {
this.ball.move();
repaint();
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
this.start = true;
}
this.player.pressed(e.getKeyCode());
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void actionPerformed(ActionEvent e) {
if (!this.gameOver && this.start) {
this.update();
}
}
}
class Blocks {
private final int x;
private final int y;
private final int width;
private final int height;
public Blocks(int a, int b, int w, int h) {
this.x = a;
this.y = b;
this.width = w;
this.height = h;
}
public void paint(Graphics g) {
g.setColor(Color.pink);
g.drawRect(this.x, this.y, this.width, this.height);
g.fillRect(this.x, this.y, this.width, this.height);
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
}
public class Paddle {
private int x;
private final int y;
private final int width;
private final int height;
private final int posun;
private final Breaker game;
/**
*
* @param game
*/
public Paddle(Breaker game) {
this.x = 245 - (60/2);
this.y = 540;
this.width = 100;
this.height = 15;
this.posun = 10;
this.game = game;
}
public int getWidth() {
return this.width;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public void paint(Graphics g) {
g.setColor(Color.CYAN);
g.drawRect(this.x, this.y, this.width, this.height);
g.fillRect(this.x, this.y, this.width, this.height);
}
void pressed(int keyCode) {
this.collision();
if (keyCode == KeyEvent.VK_RIGHT) {
this.x += this.posun;
} else if (keyCode == KeyEvent.VK_LEFT) {
this.x -= this.posun;
}
}
private void collision() {
if ((this.x + this.width) >= 490) {
this.x = 490 - this.width;
} else if (this.x <= 0) {
this.x = 0;
}
}
}
public class Ball {
private final int DIAMETER = 20;
private int x;
private int y;
private int dx;
private int dy;
private final Breaker game;
/**
*
* @param game
*/
public Ball(Breaker game) {
this.x = 245 - (DIAMETER / 2);
this.y = 500;
this.dx = 2;
this.dy = 2;
this.game = game;
}
void paint(Graphics g) {
g.setColor(Color.PINK);
g.drawOval(this.x, this.y, DIAMETER, DIAMETER);
g.fillOval(this.x, this.y, DIAMETER, DIAMETER);
}
private void checkCollision() {
boolean collision = false;
if (((this.y+DIAMETER) >= this.game.getPanel().getPlayer().getY()) && ((this.x) >= this.game.getPanel().getPlayer().getX()-2) && ((this.x+DIAMETER) <= (this.game.getPanel().getPlayer().getX()+this.game.getPanel().getPlayer().getWidth()+2))) {
collision = true;
} else if ((this.y + DIAMETER) >= 560) {
this.game.getPanel().isGameOver();
return;
}
for (Blocks block : this.game.getPanel().getBlocks()) {
if ((this.y+5 <= (block.getY() + block.getHeight())) && (this.x+5 >= block.getX()) && ((this.x+DIAMETER-5) <= block.getX()+block.getWidth())) {
this.game.getPanel().getBlocks().remove(block);
collision = true;
this.game.getPanel().addPoint();
break;
}
}
if (collision) {
this.dy = - this.dy;
}
}
public void move() {
if (this.x <= 0 || this.x >= (460 + DIAMETER)) {
this.dx = -this.dx;
} else if (this.y <= 0 || this.y >= (540 + DIAMETER)) {
this.dy = -this.dy;
}
this.checkCollision();
this.x += this.dx;
this.y += this.dy;
}
}
-
\$\begingroup\$ Welcome to Code Review! While one user has corrected formatting for the closing braces, refer to Tips for formatting code using markdown \$\endgroup\$Sᴀᴍ Onᴇᴌᴀ– Sᴀᴍ Onᴇᴌᴀ ♦2020年08月24日 22:10:31 +00:00Commented Aug 24, 2020 at 22:10
1 Answer 1
Nice, one of my favorite games.
What you got now is all the responsibilities of a program mixed together into same classes merrily violating the single responsibility principle. Study the MVC model. Then start by separating your game physics into their own set of classes and the graphical representation to another set. Put the key and action listeners into their own classes and create a main class that connects all the components together.
Move all the magic numbers (such as screen size) into variables so that you can change them easily. Make the object sizes relative to the screen size so that you can scale the game for different screen resolutions. Take into account that not all screens have the same width to height aspect ratio.
Avoid arbitrary abbreviations like posun
. What is a posun?