我正在尝试创建一个突破游戏,但是我发现了关于游戏“场景”面板大小的讨厌问题。JPanel的宽度超过了getPreferredSize()中定义的尺寸()
这是我的Board
类,这是在游戏的所有组分被分布在面板:
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);
}
}
在上面的代码中,可以看出,我设置的宽度和高度根据固定值,并且我重写了preferredSize()
方法以遵守这些措施。
问题是具有屏幕边缘的碰撞逻辑基于我在JPanel
中设置的那些测量,但由于某种原因,它在右侧获得了额外的空间,正如球和桨的碰撞可以看出的那样在下面的GIF右下角:
我想这个问题可能与this other doubt,但JPanel
内发生的额外空间。
在球类,式我使用以检测右角边界扭转方向是在move()
方法既类:
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;
}
[...]
}
类桨:
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;
}
}
如何通过保持JPanel的大小来消除这个空间?
作为一个可测试片段将在大的问题,我在Gist加入含有所涉及的所有类(Ball
,Paddle
和Board
)的可执行代码。
'作为一个可测试的代码片段在这个问题上会很大,' - 为什么? Paddle类与问题无关。所有你需要的是董事会,球和框架。菜单栏也是无关紧要的。 [mcve]的要点是为了简化代码,以便您可以专注于与问题直接相关的逻辑。 – camickr
'要点中的例子是最小,完整和可验证的例子,只是' - 不是那整个应用程序的转储。你的问题是关于球,以及它如何反弹到面板两侧。其他代码与您的问题无关。我已经给你提供了不必要代码的例子。 “MCVE”的意义在于简化问题。我们没有时间查看数百行代码。所以你简化了代码,以便它仍然是可执行的。 – camickr
@camickr同样的问题也会影响Paddle类。出于这个原因,我添加了球,桨和板类。所有三个类中都有更多的代码,为了简化执行,我删除了这些代码。 – Articuno