2011-10-22 119 views
2

我打了另一堵牆。讓我的鍵盤輸入的工作,我已經絞盡了幾個小時的大腦之後,我想創建一個暫停功能,因此,如果相同的密鑰再次按下TimerTask的停止運行(即遊戲暫停)暫停一個計時器任務

JPanel component = (JPanel)frame.getContentPane(); 
    component.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "space"); 
    component.getActionMap().put("space", (new AbstractAction(){ 
     public void actionPerformed(ActionEvent e){ 

      Timer timer = new Timer(); 

      timer.scheduleAtFixedRate(new TimerTask(){ 
      public void run(){ 
        grid.stepGame(); 
       } 
      },250, 250); 



     }})); 


     } 

問題是我不能使用全局布爾isRunning var,並且每次按鍵時都要切換它,因爲嵌套類中的timerTask方法(所以布爾isRunning必須被聲明爲最終才能被訪問......)。關於如何檢測鍵是否再次被按下或者遊戲已經運行的任何想法,所以我可以暫停/取消我的timerTask。

非常感謝薩姆

+0

查看使用代碼更新。再次使用*** Swing *** Timer,而不是java.util.Timer。 –

回答

6

由於這是一個Swing的遊戲,你應該使用javax.swing.Timer或Swing Timer而不是java.util.Timer。通過使用Swing Timer,您可以保證在EDT上調用間歇調用的代碼,這是Swing應用程序的一個關鍵問題,它也有一個停止方法來暫停計時器。您還可以爲匿名AbstractAction類提供一個私有布爾字段來檢查該鍵是否第一次被按下。

此外,榮譽和1+使用密鑰綁定而不是KeyListener。

例如,

JPanel component = (JPanel) frame.getContentPane(); 
    component.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "space"); 
    component.getActionMap().put("space", (new AbstractAction() { 
    private boolean firstPress = true; 
    private int timerDelay = 250; 
    private javax.swing.Timer keyTimer = new javax.swing.Timer(timerDelay , new ActionListener() { 

     // Swing Timer's actionPerformed 
     public void actionPerformed(ActionEvent e) { 
      grid.stepGame(); 
     } 
    }); 

    // key binding AbstractAction's actionPerformed 
    public void actionPerformed(ActionEvent e) { 
     if (firstPress) { 
      keyTimer.start(); 
     } else { 
      keyTimer.stop(); 
     } 

     firstPress = !firstPress; 
    } 
    })); 

另一個有用的選項是對按鍵執行重複任務,並停止其在鍵釋放,這樣就可以很容易地通過獲取擊鍵對報刊和發佈來完成:

KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true) // for key release 
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false) // for key press 

例如:

import java.awt.event.*; 
import javax.swing.*; 

public class SwingTimerEg2 { 
    private JFrame frame; 
    private Grid2 grid = new Grid2(this); 
    private JTextArea textarea = new JTextArea(20, 20); 
    private int stepCount = 0; 

    public SwingTimerEg2() { 
     frame = new JFrame(); 

     textarea.setEditable(false); 
     frame.add(new JScrollPane(textarea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
      JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)); 

     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
     setUpKeyBinding(); 
    } 

    void setUpKeyBinding() { 
     final int timerDelay = 250; 
     final Timer keyTimer = new Timer(timerDelay, new ActionListener() { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      grid.stepGame(); 
     } 
     }); 
     JPanel component = (JPanel) frame.getContentPane(); 
     final int condition = JComponent.WHEN_IN_FOCUSED_WINDOW; 
     final String spaceDown = "space down"; 
     final String spaceUp = "space up"; 
     component.getInputMap(condition).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), spaceDown); 
     component.getActionMap().put(spaceDown, (new AbstractAction() { 
     public void actionPerformed(ActionEvent e) { 
      keyTimer.start(); 
     } 
     })); 
     component.getInputMap(condition).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), spaceUp); 
     component.getActionMap().put(spaceUp, (new AbstractAction() { 
     public void actionPerformed(ActionEvent e) { 
      keyTimer.stop(); 
     } 
     })); 

    } 

    public void doSomething() { 
     textarea.append(String.format("Zap %d!!!%n", stepCount)); 
     stepCount ++; 
    } 

    private static void createAndShowGui() { 
     new SwingTimerEg2(); 
    } 

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

} 

class Grid2 { 
    private SwingTimerEg2 stEg; 

    public Grid2(SwingTimerEg2 stEg) { 
     this.stEg = stEg; 
    } 

    void stepGame() { 
     stEg.doSomething(); 
    } 
} 
+0

好建議+1 – mKorbel

0

最簡單,最骯髒的解決方案:

final boolean[] isRunning = new boolean[1]; 

你不想這樣做,但它的作品圍繞假設正確的同步。

什麼是更好的

final AtomicBoolean isRunning = new AtomicBoolean(); 

什麼是更好的是再次審查設計:全球狀態通常表示,「全球問題」

+0

我會記住這一點,雖然哈哈很骯髒 –

+0

看到更新:)如果我正在編寫一個遊戲,我會提取整個遊戲狀態在一個單獨的實體,如果你願意的話可以提取一個外觀 - 並且查詢當前狀態。但是,如果你只需要一個標誌,請參閱上面:) – alf

0

最終限定符要求可以很容易地b e避免 - 用一個類方法調用來替換你的內部方法(它具有final要求)。

0

不,你有錯誤的想法,爲什麼你需要最終的匿名類!最終只需要局部變量(更確切地說,任何變量的實時時間可能短於給定的對象)。

因此,一個類中的靜態變量是非常好的,將完美的工作!

編輯:例如:

public class Main { 
    interface Test { 
     void call(); 
    } 

    public static volatile boolean running = true; 

    public static void main(String[] args) { 
     Test t = new Test() { 
      @Override 
      public void call() { 
       System.out.println(Main.running); 
      } 
     }; 
     t.call(); 
     running = false; 
     t.call(); 
    } 
} 
+0

不需要靜態或不穩定。這一切都是在EDT的一個線程上完成的,因此揮發性也是不必要的。此外,任何布爾字段都可以是其匿名內部類的私有實例字段,因此不需要靜態。 –

+0

@HovercraftFullOfEels不使用靜態會使示例不必要的複雜而沒有任何收益。而且,如果他使用'java.util.Timer',那麼揮發性顯然是必要的(或者後來想停止遊戲邏輯中的動作,這在我的經驗中遲早是必需的)。此示例的整個想法是顯示如果編譯器可以保證變量的實時時間至少與類的時間一樣長,那麼您不需要最終的約束 - 這正是我在上面的段落中所寫的內容:p – Voo

+0

他不應該是使用java.util.Timer,因爲這是一個Swing應用程序。請參閱我的示例,瞭解如何在不使用任何靜態圖的情況下執行此操作。 –

0

保持到定時器某處的參考,比如在你的遊戲類。 遊戲暫停時取消定時器。 這將取消當前計劃的任務。 然後,當遊戲未暫停時,再按照上面所做的那樣安排定時器。

public class Game { 

    private Timer timer; 

    public void pause() { 
     if (timer != null) { 
      timer.pause(); 
     } 
    } 

    public void startOrResumeGame() { 
     if (timer == null) { 
      timer = new Timer(); 
     } else { 
      // Just in case the game was already running. 
      timer.cancel(); 
     } 
     timer.scheduleAtFixedRate(new TimerTask() { 
      public void run() { 
        grid.stepGame(); 
       } 
      }, 250, 250); 

    } 
}