2011-04-12 62 views
0

我一直在做俄羅斯方塊遊戲,它幾乎完成。我有KeyEvents和Timer的問題。Java Timer&KeyEvents問題

我的計時器每隔400毫秒調用一次actionPerformed,這會下降俄羅斯方塊。問題是,如果我按鍵盤上的某些東西(向下,向左,向右等),這些命令也會每400毫秒記錄一次。我怎樣才能讓計時器每隔400毫秒撥打電話actionPerformed,但我可以隨時按幾次按鍵盤上的某個鍵,並立即識別/響應該按鍵?

編輯:下面是一些代碼就像人問

public class Game extends JPanel implements ActionListener { 

public static final HashMap<Character, Color> colors = new HashMap<Character,Color>(); 
Timer timer; 
Block kpl; 
Grid gameBoard; 
char[][] grid; 
boolean paused = false; 

public Game() { 

    colors.put('P', Color.blue); colors.put('S', Color.green); 
    colors.put('D', Color.pink); colors.put('L', Color.red); 
    colors.put('Z', Color.orange); colors.put('A', Color.cyan); 
    colors.put('T', Color.magenta); 
    kpl = new Block(); 
    gameBoard = new Grid(21,10); // 21x10 sized gameboard 
    grid = gameBoard.getGrid(); 
    addKeyListener(new KeyListening()); 
    setDoubleBuffered(true); 
    setFocusable(true); 
    timer = new Timer(100, this); 
    timer.start(); 

} 

@Override 
public void paint(Graphics g) { // draws the current game situation 
    super.paint(g); 

     int height = getHeight()/grid.length; 
     int width = getWidth()/grid[0].length/2; 


     for (int row = 0; row < grid.length; ++row) { 
      for (int column = 0; column < grid[row].length; ++column) { 

       if (grid[row][column] == '.') { // if empty, paint white 
        g.setColor(Color.white); 
        g.fillRect(column*width, row*height , width, height); 
        g.setColor(Color.LIGHT_GRAY); 
        g.drawRect(column*width, row*height , width, height); 
       } 
       else if (grid[row][column] != '.') { // if not empty, paint with the color of the block 
        g.setColor(colors.get(grid[row][column])); 
        g.fillRect(column*width, row*height , width, height); 
        g.setColor(Color.BLACK); 
        g.drawRect(column*width, row*height , width, height); 
       } 
      } 
     } 

    Toolkit.getDefaultToolkit().sync(); 
    g.dispose(); 
} 



public void actionPerformed(ActionEvent e) { 
    if (!gameBoard.isFallingBlock()) 
     gameBoard.drop(kpl); // if not any falling blocks, drops a new block 

    gameBoard.updateView(); // moves the block down 
    repaint(); 
} 

    private class KeyListening extends KeyAdapter { 

    @Override 
    public void keyPressed(KeyEvent e) { 

     int key = e.getKeyCode(); 

     switch (key) { 
      case KeyEvent.VK_LEFT: 
       gameBoard.move("v"); // moves block left 
       break; 
      case KeyEvent.VK_RIGHT: 
       gameBoard.move("o"); // moves block right 
       break; 
      case KeyEvent.VK_DOWN: 
       gameBoard.updateView(); // moves block down 
       break; 
      case KeyEvent.VK_SPACE: 
       gameBoard.move("p"); // drops the block to the bottom 
       break; 
      case KeyEvent.VK_UP: // rotates block 
       gameBoard.move("k"); 
       break; 
      case KeyEvent.VK_P: // makes the game pause 
       if (paused) { 
        timer.start(); 
        paused = false; 
        return; 
       } 

       timer.stop(); 
       paused = true; 
       break; 

     } 

    } 

} 

}

自那時以來,我一直用我自己的語言對其進行命名變量來翻譯一點點。 GUI也很簡單,因爲我首先製作了我的俄羅斯方塊的文本版本,所以它基本上在後臺運行它的文本版本,並且描繪了遊戲的情況。

文字版本身是char類型化矩陣,其中我移動塊,例如:

..P.. 
..ppp 
..... 
..... 

解決:

問題解決了!在公共無效的keyPressed()後,每命令通過鍵盤來我就叫重繪() - 再次方法類似

 public void keyPressed(KeyEvent e) { 

     int key = e.getKeyCode(); 
     switch (key) { 
      case KeyEvent.VK_LEFT: 
       gameBoard.move("v"); 
       repaint(); 
       break; 

本來我的比賽回答了我的鍵盤立刻命令,但在的actionPerformed吸引了遊戲的當前狀態,每400毫秒( )repaint()被調用的地方。現在我的塊可以隨時移動,無需任何「延遲」,並且每400ms仍然穩定下降:)

+0

沒有足夠的信息來解決這個問題。這不應該發生。您必須提供更多關於KeyEvents正在發生的事情的信息,例如顯示一小段代碼。 – 2011-04-12 11:49:05

+0

可以請在這裏發佈代碼,以便我們有明確的想法! – 2011-04-12 11:50:03

+0

您尚未發佈所有代碼。這可能是一個延遲問題的事件,或重新獲得延遲問題。你可以通過在KeyPressed(KeyEvent e)的頂部放置一個System.out.println來找出它是哪個問題? – 2011-04-12 16:31:17

回答

0

您可能想看看Key Bindings及其在同一頁底部的示例。

tips4java blog摘自:

Action action = new AbstractAction() {...}; 
KeyStroke keyStroke = KeyStroke.getKeyStroke("control Z"); 
InputMap im = component.getInputMap(...); 
component.getActionMap().put(im.get(keyStroke), action); 

分享的:

Action action = new AbstractAction() {...}; 
String keyStrokeAndKey = "control Z"; 
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyStrokeAndKey); 
component.getInputMap(...).put(keyStroke, keyStrokeAndKey); 
component.getActionMap().put(keyStrokeAndKey, action); 

改變現有的以替換現有綁定的操作功能:

通過添加新鍵綁定添加新功能用不同的KeyStroke動作:

KeyStroke existingKeyStroke = KeyStroke.getKeyStroke("ENTER"); 
KeyStroke addedKeyStroke = KeyStroke.getKeyStroke("control Z"); 
InputMap im = component.getInputMap(...); 
im.put(addedKeyStroke, im.get(existingKeyStroke)); 

刪除鍵結合:

KeyStroke remove = KeyStroke.getKeyStroke(...); 
InputMap im =component.getInputMap(...); 
im.put(remove, "none"); 

注意,上述實施例是用於將綁定單個組件。要添加你需要使用根窗格的InputMap和ActionMap中的框架或對話級別綁定:

frame.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)... 
frame.getRootPane().getActionMap()... 
0

你需要確保你使用的是搖擺Timer並沒有阻止事件調度線程。很可能你需要一個單獨的actionPerformed方法來處理關鍵事件,而不是塊丟失。

0

我想嘗試降低定時器的時間間隔,使按鍵更加敏感,並使用一個計數器來一次下拉塊中的每個這麼多的間隔。

+0

這僅僅是這並沒有解決真正的問題一個黑客。 – 2011-04-12 12:43:54

+0

@Robin這根本不是黑客!事實上,大多數遊戲(包括是的,俄羅斯方塊)都是以這種方式運作的。我會盡可能地說提問者的「解決方案」是真正的黑客。重新繪製每個按鍵的遊戲畫面,ack。 – epaik 2011-04-13 20:14:40

+0

這不是在ZX頻譜上編程的。我想象這臺電腦能夠在每次按鍵時重新畫上屏幕。 – 2011-04-14 10:59:27