Java JPanel宽度超过getPreferredSize()中定义的维度
我试图创建一个突破游戏,但我发现了一个关于游戏“场景”面板大小的恼人问题 这是我的Java JPanel宽度超过getPreferredSize()中定义的维度,java,swing,graphics2d,Java,Swing,Graphics2d,我试图创建一个突破游戏,但我发现了一个关于游戏“场景”面板大小的恼人问题 这是我的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;
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中右角的球和桨的碰撞所示:
我认为问题可能与有关,但额外的空间出现在JPanel
中
在Ball类中,我用于检测右角边界以反转方向的公式位于两个类的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;
}
[...]
}
导入java.awt.Graphics2D;
导入java.awt.Rectangle;
公共班级舞会{
私有整数x=0;
私人智力y=15;
专用最终内径=30;
私有int xSpeed=1;
私用int-ySpeed=1;
私人终审委员会;
私人决赛;
公众舞会(董事会){
this.board=董事会;
this.paile=board.paile;
y=桨。getTopY()-直径;
x=板宽/2-直径/2;
}
公开作废动议(){
如果(x>=board.WIDTH-DIAMETER | | x paile.getTopY()+paile.HEIGHT){
board.gameOver();
}
if(碰撞()){
浮动桨中心=桨.getX()+(桨.WIDTH/2);
浮动相对速度=此.x+(直径/2)-桨叶中心/(桨叶宽度/2);
if((相对速度>0&&xSpeed<0)| |(相对速度<0&&xSpeed>0)){
xSpeed=-xSpeed;
}
ySpeed=-ySpeed;
y=桨。getTopY()-直径;
}
x+=x速度;
y+=y速度;
}
[...]
}
班级桨:
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;
}
}
导入java.awt.Graphics2D;
导入java.awt.Rectangle;
导入java.awt.event.KeyEvent;
公务舱桨{
私有整数x=0;
私人终审法院;
公共最终整数宽度=100;
公共最终内部高度=10;
私有int方向=0;
私人董事会;
公共挡板(板){
this.board=董事会;
topY=板高度;
x=板宽/2-宽度/2;
}
公开作废动议(){
如果(x+方向>=0&&x+方向我们不知道应用程序是如何构建的。例如,您是否直接将板面板添加到框架中?或者您将板面板嵌套到另一个面板中,并且看到的额外空间来自父面板
您是否尝试将LineBorder
添加到板面板。如果边框绘制正确,但球仍然没有到达边缘,则说明碰撞逻辑有问题
setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
这是没有意义的,因为你正在做球和桨的自定义绘制。如果有任何布局应该为空
编辑:
这看起来很可疑:
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
打包()框架,然后更改框架的属性。由于框架不可调整大小,因此无需绘制边框,因此边框的额外宽度现在添加到面板中,但逻辑检查的是硬编码值,而不是面板的实际宽度
代码应为:
//frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
请注意,问题与您发布的代码无关
这就是为什么一个合适的MCVE
应该与每个问题一起发布在论坛上,而不是发布在另一个网站上!!!作为一个可测试的片段,问题会很大,
-为什么?桨类与问题无关。你所需要的只是板、球和框架。菜单栏也不相关。问题的关键是f或者你可以简化代码,以便专注于与问题直接相关的逻辑。要点中的示例是最小的、完整的、可验证的示例,只是
-不,这是整个应用程序的转储。你的问题是球以及它如何在面板侧反弹。其他代码与你的问题无关。我已经给了你一些不必要代码的例子。MCVE
的目的是简化问题。我们没有时间看几百行代码。所以你简化了代码,使它仍然可以执行。@camickr同样的问题也会影响到桨类。因此,我添加了Ball、patle和Board类。There是所有三个类中的更多代码,我删除了它以简化执行。仅供将来参考FlowLayout是JPanels的默认布局,无需将其设置为该布局。Board类被添加为“contentpane”当然是JFrame。只要在窗口中有这个JPanel。我在JPanel中为score添加了2个JLabel,所以我使用了这个布局。标签可能应该在添加到框架的页面开始的单独面板上。在任何情况下,如果您验证了面板的边框是正确的,那么正如我所说的,问题是您的冲突检测逻辑。So您只需要进行基本调试。逐步完成逻辑,确保所有变量的值都是您期望的值。显然,您在某个地方存在边界问题。@diegofm,您还可以查看:对于一些球动画。只需将球的数量更改为1,以查看其反应。球的边缘始终接触到球的侧面面板。你甚至可以调整框架的大小。因此,这里使用的逻辑可能有助于发现你的逻辑问题。我在move方法中使用的逻辑与你在这段代码中使用的逻辑相同。为了进行测试,我在JPanel内画了一个宽度为400的小矩形,并且还有一个空格。球忽略了相同的空格。