2017-05-11 18 views
1

我正在尝试创建一个突破游戏,但是我发现了关于游戏“场景”面板大小的讨厌问题。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右下角:

enter image description here

我想这个问题可能与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加入含有所涉及的所有类(BallPaddleBoard)的可执行代码。

+1

'作为一个可测试的代码片段在这个问题上会很大,' - 为什么? Paddle类与问题无关。所有你需要的是董事会,球和框架。菜单栏也是无关紧要的。 [mcve]的要点是为了简化代码,以便您可以专注于与问题直接相关的逻辑。 – camickr

+1

'要点中的例子是最小,完整和可验证的例子,只是' - 不是那整个应用程序的转储。你的问题是关于球,以及它如何反弹到面板两侧。其他代码与您的问题无关。我已经给你提供了不必要代码的例子。 “MCVE”的意义在于简化问题。我们没有时间查看数百行代码。所以你简化了代码,以便它仍然是可执行的。 – camickr

+0

@camickr同样的问题也会影响Paddle类。出于这个原因,我添加了球,桨和板类。所有三个类中都有更多的代码,为了简化执行,我删除了这些代码。 – Articuno

回答

1

那么我们不知道你的应用程序如何构建的上下文。例如,你是否将Board面板直接添加到框架?或者,您可能正在将Board面板嵌套到另一个面板中,而您看到的额外空间来自于父面板?

您是否尝试在面板中添加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应该发布在论坛上与每个问题,而不是在另一个网站上!

+0

将Board类添加为JFrame的“contentpane”。只要在窗口中有这个JPanel。我在JPanel中添加了2个JLabels作为分数,所以我使用了这个布局。 – Articuno

+0

那么标签应该放在一个单独的面板上,并添加到框架的PAGE_START中。在任何情况下,如果您验证面板的边框是正确的,那么正如我所说的问题是您的碰撞检测逻辑。所以你只需要做基本的调试。通过逻辑确定所有变量的值是你期望的值。你显然有一个边界问题的地方。 – camickr

+1

@diegofm,你也可以看看:http://stackoverflow.com/questions/42678570/java-random-placement-of-objects/42679448#42679448对于一些球动画。只要将球的数量改为1,看看它是如何反应的。球的边缘总是接触面板的一侧。你甚至可以调整框架的大小。所以也许在那里使用的逻辑将有助于找到你的逻辑问题。 – camickr