2014-02-15 50 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,会出现同样的问题吗? –