2012-11-23 71 views
1

我正在嘗試構建一個平臺,但我一直在探索如何檢測多個按鍵。例如,如果我正在使用運行鍵並向前跑,然後我點擊跳轉鍵,遊戲仍然需要知道是否正在按運行鍵在java中檢測多個按鍵

+0

也許在按鍵上設置布爾值,並在按鍵釋放時取消設置它們? – Quetzalcoatl

+0

http://stackoverflow.com/questions/752999/how-do-i-handle-multiple-key-press-in-java – AurA

+0

可能的重複[字符的鍵組合(非Ctrl或Alt)在Java](http://stackoverflow.com/questions/8464727/key-combination-of-characters-non-ctrl-or-alt-in-java) – kleopatra

回答

1

試試這個使用HashSet來保持軌跡的自定義類的按鍵...

class MultiKeyPressListener implements KeyListener { 

    // Set of currently pressed keys 
    private final Set<Character> pressed = new HashSet<Character>(); 

    @Override 
    public synchronized void keyPressed(KeyEvent e) { 
     pressed.add(e.getKeyChar()); 
     if (pressed.size() > 1) { 
      // More than one key is currently pressed. 
      // Iterate over pressed to get the keys. 
     } 
    } 

    @Override 
    public synchronized void keyReleased(KeyEvent e) { 
     pressed.remove(e.getKeyChar()); 
    } 

    @Override 
    public void keyTyped(KeyEvent e) {/* Not used */ } 
} 
+2

基本上正確,你需要邏輯來跟蹤哪些鍵在按狀態,僅:不使用keyListeners ...而是使用keyBindings – kleopatra

2

這是一個更復雜,然後我會正常做。通常我會允許每個Action直接改變遊戲狀態。

本示例說明如何使用key bindings API監視特定按鍵的按下/釋放並將其從中央池添加/刪除。

使用此API的主要原因是它克服了焦點上下文中KeyListener的限制。只要窗口具有焦點,此示例將檢索按鍵通知。

public class TestMultyKeyPress { 

    public static void main(String[] args) { 
     new TestMultyKeyPress(); 
    } 

    public TestMultyKeyPress() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException ex) { 
       } catch (InstantiationException ex) { 
       } catch (IllegalAccessException ex) { 
       } catch (UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame("Test"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new KeyPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 

     }); 
    } 

    public class KeyPane extends JPanel implements KeyManager { 

     private TrianglePane upPane; 
     private TrianglePane downPane; 
     private TrianglePane leftPane; 
     private TrianglePane rightPane; 
     private List<Integer> keysList = new ArrayList<>(25); 

     public KeyPane() { 
      setLayout(new GridBagLayout()); 
      upPane = new TrianglePane(0); 
      leftPane = new TrianglePane(1); 
      downPane = new TrianglePane(2); 
      rightPane = new TrianglePane(3); 
      GridBagConstraints gbc = new GridBagConstraints(); 
      gbc.gridx = 1; 
      gbc.gridy = 0; 
      add(upPane, gbc); 

      gbc.gridx = 0; 
      gbc.gridy++; 
      add(leftPane, gbc); 
      gbc.gridx += 2; 
      add(rightPane, gbc); 

      gbc.gridx = 1; 
      gbc.gridy++; 
      add(downPane, gbc); 

      InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW); 
      ActionMap am = getActionMap(); 

      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "KeyPressed.Left"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "KeyPressed.Right"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "KeyPressed.Up"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "KeyPressed.Down"); 

      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "KeyReleased.Left"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "KeyReleased.Right"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "KeyReleased.Up"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "KeyReleased.Down"); 

      am.put("KeyPressed.Left", new KeyAction(KeyEvent.VK_LEFT, false, this)); 
      am.put("KeyPressed.Right", new KeyAction(KeyEvent.VK_RIGHT, false, this)); 
      am.put("KeyPressed.Up", new KeyAction(KeyEvent.VK_UP, false, this)); 
      am.put("KeyPressed.Down", new KeyAction(KeyEvent.VK_DOWN, false, this)); 

      am.put("KeyReleased.Left", new KeyAction(KeyEvent.VK_LEFT, true, this)); 
      am.put("KeyReleased.Right", new KeyAction(KeyEvent.VK_RIGHT, true, this)); 
      am.put("KeyReleased.Up", new KeyAction(KeyEvent.VK_UP, true, this)); 
      am.put("KeyReleased.Down", new KeyAction(KeyEvent.VK_DOWN, true, this)); 

     } 

     @Override 
     public void keyPressed(int keyCode) { 
      if (!keysList.contains(keyCode)) { 
       keysList.add(new Integer(keyCode)); 
       updateKeyState(); 
      } 
     } 

     @Override 
     public void keyReleased(int keyCode) { 
      keysList.remove(new Integer(keyCode)); 
      updateKeyState(); 
     } 

     public void updateKeyState() { 
      upPane.setActive(keysList.contains(KeyEvent.VK_UP)); 
      downPane.setActive(keysList.contains(KeyEvent.VK_DOWN)); 
      leftPane.setActive(keysList.contains(KeyEvent.VK_LEFT)); 
      rightPane.setActive(keysList.contains(KeyEvent.VK_RIGHT)); 
     } 

    } 

    public interface KeyManager { 

     public void keyPressed(int keyCode); 

     public void keyReleased(int keyCode); 

    } 

    public class KeyAction extends AbstractAction { 

     private int keyCode; 
     private boolean released; 
     private KeyManager manager; 

     public KeyAction(int keyCode, boolean released, KeyManager manager) { 
      this.keyCode = keyCode; 
      this.released = released; 
      this.manager = manager; 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      if (released) { 
       manager.keyReleased(keyCode); 
      } else { 
       manager.keyPressed(keyCode); 
      } 
     } 

    } 

    public class TrianglePane extends JPanel { 

     private boolean active; 
     private TriangleShape shape; 

     public TrianglePane(int direction) { 

      shape = new TriangleShape(20); 
      AffineTransform at = null; 
      switch (direction) { 
       case 0: 
        at = AffineTransform.getRotateInstance(Math.toRadians(-90), 10, 10); // UP 
        break; 
       case 1: 
        at = AffineTransform.getRotateInstance(Math.toRadians(180), 10, 10); // UP 
        break; 
       case 2: 
        at = AffineTransform.getRotateInstance(Math.toRadians(90), 10, 10); // UP 
        break; 
       case 3: 
        at = AffineTransform.getRotateInstance(Math.toRadians(0)); // UP 
        break; 
      } 
      shape.transform(at); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(20, 20); 
     } 

     public void setActive(boolean value) { 
      if (active != value) { 
       this.active = value; 
       repaint(); 
      } 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      int x = (getWidth() - shape.getBounds().width)/2; 
      int y = (getHeight() - shape.getBounds().height)/2; 
      if (active) { 
       g2d.setColor(Color.BLACK); 
      } else { 
       g2d.setColor(Color.GRAY); 
      } 
      g2d.fill(shape); 
     } 

    } 

    public class TriangleShape extends Path2D.Float { 

     public TriangleShape(int size) { 
      moveTo(1, 1); 
      lineTo(size - 1, (size - 1)/2); 
      lineTo(1, size - 1); 
      closePath(); 
     } 

    } 

}