2014-02-15 76 views
1

我已經構建了俄羅斯方塊遊戲。現在我已經使用JPanel來顯示內容和塊(使用paintComponents()方法)。重新繪製不能正常運行

的問題是每當我試圖從另一個JFrame中它不畫都稱之爲俄羅斯方塊程序。

的代碼爲我的俄羅斯方塊主菜單是:

import javax.swing.*; 
import sun.audio.AudioPlayer; 
import sun.audio.AudioStream; 
import java.awt.*; 
import java.awt.event.*; 
import java.io.FileInputStream; 
import java.io.InputStream; 

@SuppressWarnings("serial") 
public class Tetris_MainMenu extends JFrame implements ActionListener { 

    @SuppressWarnings("unused") 
    public static void main(String[] args) { 

     Tetris_MainMenu tmm = new Tetris_MainMenu(); 
     playAudio("doak.wav"); 

    } 

    JPanel logo = new JPanel(); 
    JPanel buttonPanel = new JPanel(new GridLayout(4, 1)); 

    JButton start = new JButton("START NEW GAME"); 
    JButton help = new JButton("INSTRUCTIONS"); 
    JButton about = new JButton("ABOUT THIS GAME"); 
    JButton exit = new JButton("EXIT"); 

    Tetris_MainMenu(){ 

     setTitle("JAG's TETRIS"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setLocation(300, 100); 
     setSize(200, 400); 
     setEnabled(true); 
     setFocusable(true); 
     setVisible(true); 

     //adding a logo to the logo panel 

     //adding buttons to the buttonPanel 
     buttonPanel.add(start); 
     buttonPanel.add(help); 
     buttonPanel.add(about); 
     buttonPanel.add(exit); 

     //add panels to window 
     setLayout(new GridLayout(2, 1)); 
     add(logo); 
     add(buttonPanel); 

     //make buttons listen to actions 
     start.addActionListener(this); 
     help.addActionListener(this); 
     about.addActionListener(this); 
     exit.addActionListener(this); 

    } 

    @SuppressWarnings("restriction") 
    public static void playAudio(String filename) 
    { 
     InputStream in = null; 
     AudioStream as = null; 
     try{ 
      in = new FileInputStream(filename); 
      as = new AudioStream(in); 
     } 
     catch(Exception e){ 
      System.out.println("Error!!!"); 
     } 
     AudioPlayer.player.start(as); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 

     if(e.getSource() == start){ 
      this.dispose(); 
      MatrixBoard b = new MatrixBoard(); 
      b.setRequestFocusEnabled(true); 
     } 
     else if(e.getSource() == help){ 
      JOptionPane.showMessageDialog(null, "Controls:\n" 
        + "LEFT and RIGHT ARROWS: For moving blocks left and right\n" 
        + "DOWN ARROW: For dropping block immediately\n" 
        + "SPACEBAR: For rotating block\n" 
        + "e: To exit to main menu"); 
     } 
     else if(e.getSource() == about){ 
      JOptionPane.showMessageDialog(null, "Designed by: JAG." 
        + "\nIf you want you can use it for your own purposes." 
        + "\nBut give credit where it is due."); 
     } 
     else if(e.getSource() == exit){ 
      int opt = JOptionPane.showConfirmDialog(null, "Are you sure?", "Confirm Exit", JOptionPane.YES_NO_OPTION); 
      if(opt == JOptionPane.YES_OPTION){ 
       System.exit(0); 
      } 
     } 
    } 


} 

的俄羅斯方塊遊戲在新窗口中啓動時的矩陣板的構造函數被調用。但是這些塊在屏幕上不可見。 MatrixBoard的代碼是:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import java.io.*; 
import sun.audio.*; 

@SuppressWarnings("serial") 
public class MatrixBoard extends JPanel implements ActionListener{ 

    int boardHeight = 20; 
    int boardWidth = 10; 
    int score = 0; 
    int curX = 0, curY = 0; 
    int squareWidth; 
    int squareHeight; 
    Timer timer; 
    int sleepTime = 300; 
    Shape curPiece; 
    Shape.Tetromino[][] board; 
    boolean isFallingFinished = false; 
    boolean isStarted = false; 
    boolean isPaused = false; 
    JFrame f; 

    @SuppressWarnings("unused") 
    public static void main(String [] args){ 
     MatrixBoard b = new MatrixBoard();  
    } 

    public void update(Graphics g) { 

     Graphics offgc; 
     Image offscreen = null; 
     Dimension d = getSize(); 
     // create the offscreen buffer and associated Graphics 
     offscreen = createImage(d.width, d.height); 
     offgc = offscreen.getGraphics(); 
     // clear the exposed area 
     offgc.setColor(getBackground()); 
     offgc.fillRect(0, 0, d.width, d.height); 
     offgc.setColor(getForeground()); 
     // do normal redraw 
     paint(offgc); 
     // transfer offscreen to window 
     g.drawImage(offscreen, 0, 0, this); 
    } 

    @SuppressWarnings("restriction") 
    public static void playAudio(String filename) 
    { 
     InputStream in = null; 
     AudioStream as = null; 
     try{ 
      in = new FileInputStream(filename); 
      as = new AudioStream(in); 
     } 
     catch(Exception e){ 
      System.out.println("Error!!!"); 
     } 
     AudioPlayer.player.start(as); 
    } 

    MatrixBoard(){ 
     f = new JFrame("JAG's TETRIS"); 
     f.setVisible(true); 
     f.setSize(205, 400); 
     f.setFocusable(true); 
     f.setBackground(Color.GREEN); 
     f.add(this); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setSize(200, 400); 
     setVisible(true); 
     setFocusable(true); 
     requestFocusInWindow(); 
     setBackground(Color.BLACK); 
     timer = new Timer(400, this); 
     timer.setInitialDelay(10); 
     squareWidth = (getWidth())/ boardWidth; 
     squareHeight = (getHeight())/boardHeight; 
     curPiece = new Shape(); 
     board = new Shape.Tetromino[boardWidth][boardHeight]; 
     addKeyListener(new KeyHandler()); 
     clearBoard(); 
     timer.start(); 
     JOptionPane.showMessageDialog(null, "Press Enter to Start!!!"); 
     f.setEnabled(true); 
     f.setResizable(false); 
     //setEnabled(true); 
     start(); 
     System.out.println("MatrixBoard() Success!"); 
    } 

    public void clearBoard(){ 
     for(int i = 0; i < boardWidth; ++i) 
      for(int j = 0; j < boardHeight; ++j) 
       board[i][j] = Shape.Tetromino.NoShape; 
    } 

    public void start() 
    { 
     if (isPaused) 
      return; 
     clearBoard(); 
     timer.start(); 
     timer = new Timer(400, this); 
     timer.setInitialDelay(100); 
     isStarted = true; 
     isFallingFinished = false; 
     score = 0; 
     repaint(); 
     newPiece(); 
     System.out.println("START SUCCESS!"); 
    } 

    private void newPiece(){ 
     if(!isStarted) return; 
     curPiece.generateShape(); 
     curX = boardWidth/2; 
     curY = 1; 

     if(!tryMove(curPiece, curX, curY)){ 
      curPiece.selectPiece(Shape.Tetromino.NoShape); 
      isStarted = false; 
      JOptionPane.showMessageDialog(null, "Game Over! Score : " + score); 
      isStarted = false; 
      int opt = JOptionPane.showConfirmDialog(null, "Try Again?", "Again?", JOptionPane.YES_NO_OPTION); 
      if(opt == JOptionPane.YES_OPTION){ 
       start(); 
      } 
      else if (opt == JOptionPane.NO_OPTION){ 
       System.exit(0); 
      } 
      //dispose(); 
      System.exit(0); 
      //new Tetris(); 
      return; 
     } 
     dropDown(); 
     System.out.println("NEW PIECE SUCCESS!"); 
    } 

    private boolean tryMove(Shape newPiece, int newX, int newY){ 
     for(int i = 0; i < 4; i++){ 
      int x = newX + newPiece.coords[i][0]; 
      int y = newY + newPiece.coords[i][1]; 
      if(x < 0 || x >= boardWidth || y < 0 || y >= boardHeight){ 
       System.out.println("FALSE1"); 
       return false; 
      } 
      if(board[x][y] != Shape.Tetromino.NoShape){ 
       System.out.println("FALSE2"); 
       return false; 
      } 
     } 
     curPiece = newPiece; 
     curX = newX; 
     curY = newY; 
     System.out.println("curX = " + curX + " curY = " + curY); 
     System.out.println("TRY MOVE SUCCESS!"); 
     return true; 
    } 

    private void dropDown(){ 
     int newY = curY; 
     sleepTime = 300; 
     System.out.println("newY = " + newY); 
     while(newY < boardHeight){ 
      if(!tryMove(curPiece, curX, newY+1)){ break;} 
      ++newY; 
      System.out.println("calling f.update()"); 
      repaint(); 
      System.out.println("called f.update()"); 
      try { 
       Thread.sleep(sleepTime); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     pieceDropped(); 
     System.out.println("DROPDOWN SUCCESS!"); 
    } 

    private void pieceDropped(){ 

     for(int i = 0; i < 4; i++){ 
      int x = curX + curPiece.coords[i][0]; 
      int y = curY + curPiece.coords[i][1]; 
      board[x][y] = curPiece.retShape(); 
      System.out.println("PIECE: at X = " + x + " Y = " + y + "is " + curPiece.retShape().ordinal()); 
     } 
     removeFullLines(); 
     if(!isFallingFinished) newPiece(); 
     System.out.println("PIECE DROPPED SUCCESS!"); 

    } 

    public void paintComponent(Graphics g){ 

     System.out.println("PAINTED\n\n\n\n\nPAINTED!!!!"); 

     super.paintComponent(g); 

     Dimension size = getSize(); 
     int boardTop = (int) size.getHeight() - boardHeight * squareHeight; 

     System.out.println("PAINTED\n\n\n\n\nPAINTED!!!!"); 

     for (int i = 0; i < boardWidth; ++i) { 
      for (int j = 0; j < boardHeight; ++j) { 
       Shape.Tetromino shape = board[i][j]; 
       if (shape != Shape.Tetromino.NoShape) 
        drawSquare(g, i * squareWidth, 
           boardTop + j * squareHeight, shape); 
      } 
     } 

     if (curPiece.retShape() != Shape.Tetromino.NoShape) { 
      for (int i = 0; i < 4; ++i) { 
       int x = curX + curPiece.coords[i][0]; 
       int y = curY + curPiece.coords[i][1]; 
       drawSquare(g, x * squareWidth, 
          boardTop + (y - 1) * squareHeight, 
          curPiece.retShape()); 
      } 
     } 
    } 

    private void drawSquare(Graphics g, int x, int y, Shape.Tetromino shape) 
    { 
     Color colors[] = { new Color(0, 0, 0), new Color(204, 102, 102), 
      new Color(102, 204, 102), new Color(102, 102, 204), 
      new Color(204, 204, 102), new Color(204, 102, 204), 
      new Color(102, 204, 204), new Color(218, 170, 0) 
     }; 

     Color color = colors[shape.ordinal()]; 

     g.setColor(color); 
     g.fillRect(x + 1, y + 1, squareWidth - 2, squareHeight - 2); 

     g.setColor(color.brighter()); 
     g.drawLine(x, y + squareHeight - 1, x, y); 
     g.drawLine(x, y, x + squareWidth - 1, y); 

     g.setColor(color.darker()); 
     g.drawLine(x + 1, y + squareHeight - 1, 
         x + squareWidth - 1, y + squareHeight - 1); 
     g.drawLine(x + squareWidth - 1, y + squareHeight - 1, 
         x + squareWidth - 1, y + 1); 

    } 

    private void removeFullLines(){ 

     int numLines = 0; 

     for(int i = 0; i < boardHeight; i++){ 
      boolean isLineFull = true; 
      for(int j = 0; j < boardWidth; j++){ 
       System.out.println("i = " + i + " j = " + j); 
       if(board[j][i] == Shape.Tetromino.NoShape){ 
        System.out.println("Found No Shape here!"); 
        isLineFull = false; 
        break; 
       } 
      } 

      System.out.println("IIIIIIIIS LINE : " + isLineFull); 

      if(isLineFull){ 
       numLines++; 
       for(int k = i; k > 0; k--){ 
        for(int j = 0; j < boardWidth; ++j){ 
         board[j][k] = board[j][k-1]; 
        } 
       } 
      } 
     } 

     if(numLines > 0){ 
      score += numLines * numLines; 
      repaint(); 
      newPiece(); 
     } 

    } 

    class KeyHandler extends KeyAdapter{ 
     public void keyPressed(KeyEvent e){ 
      if(!isStarted || curPiece.retShape() == Shape.Tetromino.NoShape){ 
       return; 
      } 
      int keyCode = e.getKeyCode(); 

      switch(keyCode){ 
      case KeyEvent.VK_LEFT: 
       tryMove(curPiece, curX - 1, curY); 
       break; 
      case KeyEvent.VK_RIGHT: 
       tryMove(curPiece, curX + 1, curY); 
       break; 
      case KeyEvent.VK_DOWN: 
       sleepTime = 10; 
       break; 
      case KeyEvent.VK_E: 
       int opt = JOptionPane.showConfirmDialog(null,"Are you sure?", "Exit", JOptionPane.YES_NO_OPTION); 
       if(opt == JOptionPane.YES_OPTION){ 
        System.exit(0); 
       } 
       break; 
      case KeyEvent.VK_SPACE: 
       tryMove(curPiece.rotateLeft(), curX, curY); 
       break; 
      default: 
       break; 
      } 
     } 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (isFallingFinished) { 
      isFallingFinished = false; 
      newPiece(); 
     } 
    } 

} 

請幫忙。我懷疑問題出在重繪機制中,但我不確定。

回答

3

你的問題會顯示您所出現的Swing事件線程上被調用Thread.sleep(...)是一個Swing線程問題。這樣做會鎖定整個線程,凍結你的應用程序。不要這樣做,而是使用Swing Timer。

順便說一句,你不希望覆蓋update()方法Swing GUI的的因爲這是主要用於AWT GUI的,除非你改變應用程序的外觀和中期運行的感覺。


編輯
你問:

據我所知,調用Thread.sleep()方法是不可取的,最好是使用定時器。但事情是,當我單獨運行MatrixBoard時,它可以很好地工作。線程問題不在這裏。請儘可能解釋。

當你本身調用它,主要應用沒有被Swing線程上運行(這是不是一件應該做的事 - 所有Swing應用應該 Swing事件線程上運行)所以你的代碼似乎工作。一旦強制它在Swing事件線程上運行,它就會凍結。

所有的Swing GUI的應排隊上使用事件線程SwingUtilities.invokeLater(new Runnable() {...});


編輯2

關注,當你改變這個會發生什麼:

public static void main(String [] args){ 
    MatrixBoard b = new MatrixBoard();  
} 

到更合適代碼:

public static void main(String[] args){ 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
     MatrixBoard b = new MatrixBoard();  
     } 
    }); 
} 

我敢打賭你的MatrixBoard不會凍結(雖然我沒有測試過)。

+0

我知道調用Thread.sleep()是不可取的,最好使用定時器。但事情是,當我單獨運行MatrixBoard時,它可以很好地工作。線程問題不在這裏。請儘可能解釋。 –

+0

@CrystalMeth:見編輯。 –

+0

我現在明白了。如果你能指點我的參考資料或例子來幫助我解決問題,我將非常感激,因爲我對Swing非常陌生。 另一個問題:如果我使用AWT,會出現同樣的問題嗎? –