我正在嘗試創建一個突破遊戲,但是我發現了關於遊戲「場景」面板大小的討厭問題。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