3
I’m trying to create a little game Breakout, I’ve done a lot of logic, only I discovered an uncomfortable problem related to the size of the panel of the "scene" of the game.
Follow my class Board
, which is the panel where all game components are distributed:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Board extends JPanel {
private static final long serialVersionUID = 1L;
public final int WIDTH = 400;
public final int HEIGHT = 300;
private final int UPDATE_INTERVAL = 20;
private Timer timer;
public Ball ball;
public Paddle paddle;
private JLabel scoreLabel, score;
public Board() {
paddle = new Paddle(this);
ball = new Ball(this);
setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
scoreLabel = new JLabel("Score: ");
scoreLabel.setFont(getFont().deriveFont(12f));
score = new JLabel();
score.setFont(getFont().deriveFont(12f));
this.add(scoreLabel);
this.add(score);
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
paddle.keyPressed(e);
if (e.getKeyCode() == KeyEvent.VK_SPACE){
starGame();
}
}
@Override
public void keyReleased(KeyEvent e) {
paddle.keyReleased(e);
}
});
ActionListener action = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
updateBoard();
repaint();
}
};
timer = new Timer(UPDATE_INTERVAL, action);
setFocusable(true);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
private void updateBoard() {
ball.move();
paddle.move();
repaint();
}
public void gameOver() {
JOptionPane.showMessageDialog(this, "Game Over");
newGame();
}
public void starGame() {
timer.start();
}
public void stop() {
timer.stop();
}
public void newGame() {
stop();
paddle = new Paddle(this);
ball = new Ball(this);
repaint();
}
public void setSpeed(int speed) {
ball.setSpeed(speed);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2);
paddle.paint(g2);
}
}
In the above code, it can be seen that I set width and height based on fixed values, and override the method preferredSize()
to ensure that these measures are complied with.
The problem is that all logic (collisions with screen ends) is based on these measures that I defined in JPanel
, but for some reason is getting an additional space to the right, as can be seen by the bump of the ball and bat in the right corner on the gif below:
I thought the problem might be related to this other doubt, but the extra space occurs within the JPanel
and has nothing to do with the JFrame
.
In class Ball
, the formula I’m using to detect the right corner boundary and reverse the direction is in the method move()
of both classes:
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Ball {
private int x = 0;
private int y = 15;
private final int DIAMETER = 30;
private int xSpeed = 1;
private int ySpeed = 1;
private final Board board;
private final Paddle paddle;
public Ball(Board board) {
this.board = board;
this.paddle = board.paddle;
y = paddle.getTopY() - DIAMETER;
x = board.WIDTH / 2 - DIAMETER / 2;
}
public void move() {
if (x >= board.WIDTH - DIAMETER || x <= 0) {
xSpeed = -xSpeed;
}
if (y < 15) {
ySpeed = -ySpeed;
}
if (y + DIAMETER > paddle.getTopY() + paddle.HEIGHT) {
board.gameOver();
}
if (collision()) {
float paddleCenter = paddle.getX() + (paddle.WIDTH/2);
float relativePos = (this.x + (DIAMETER/2) - paddleCenter) / (paddle.WIDTH/2);
if((relativePos > 0 && xSpeed < 0) || (relativePos < 0 && xSpeed > 0)){
xSpeed = -xSpeed;
}
ySpeed = -ySpeed;
y = paddle.getTopY() - DIAMETER;
}
x += xSpeed;
y += ySpeed;
}
[...]
}
Class Paddle
:
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Paddle {
private int x = 0;
private final int topY;
public final int WIDTH = 100;
public final int HEIGHT = 10;
private int direction = 0;
private Board board;
public Paddle(Board board) {
this.board = board;
topY = board.HEIGHT;
x = board.WIDTH / 2 - WIDTH / 2;
}
public void move() {
if (x + direction >= 0 && x + direction <= board.WIDTH - WIDTH) {
x = x + direction;
}
}
public void paint(Graphics2D g2) {
g2.fillRect(x, topY, WIDTH, HEIGHT);
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
direction = -5;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
direction = 5;
}
}
public void keyReleased(KeyEvent e) {
direction = 0;
}
public Rectangle getBounds() {
return new Rectangle(x, topY, WIDTH, HEIGHT);
}
public int getTopY() {
return topY;
}
public int getX() {
return x;
}
}
How to remove this space while keeping the size of the Jpanel fixed?
As a testable example would look great in the question, Gist an executable code containing all classes(Ball
, Paddle
and Board
) involved.
Please avoid long discussions in the comments; your talk was moved to the chat
– Maniero