2017-05-11 45 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