2013-05-02 6 views
6

Ich mache ein sehr einfaches Pong-Spiel in Java und ich mache das mit KeyListener. Ich will es so, wenn der Benutzer die rechte oder linke Taste auf der Tastatur drückt, geht der Pongblock in diese Richtung. Das ist eine einfache Aufgabe, aber ich stelle fest, dass wenn der Benutzer den Schlüssel gedrückt hält, der Block sich einmal bewegt, für eine kurze Zeit anhält und dann weitergeht, bis der Benutzer den Schlüssel loslässt. Ich merke das passiert, wenn Sie versuchen, einen Buchstaben-Schlüssel auf einem Computer zu halten. Wenn ich versuche, das ‚a‘ Taste gedrückt halten, wird der Computer tun:Java KeyListener stottert

eine [Pause] AAAAAAAAAAAAAAAA

Gibt es irgendwie dieses Stottern zu deaktivieren, weil es in der Art und Weise des Erhaltens flüssiges Gameplay für mein kleines Spiel. Eine schnelle Lösung würde sehr geschätzt werden.

Antwort

5
  1. Sie sollten Key Bindings verwenden, da sie die Mehrheit der Fokus Fragen und sind in der Regel flexibler ...
  2. Sie müssen definieren, eine Flagge, um anzuzeigen, wenn eine Taste gedrückt wird, lösen. Während gedrückt, sollten Sie alle zusätzlichen Aufgaben nicht ausführen ...

Beispiele ...

Aktualisiert mit simpl Beispiel

In den meisten Spielen sollten Sie eher auf "Statusänderungen" als auf tatsächliche Schlüsselereignisse reagieren. Dies bedeutet, dass das Ereignis, das der Staat tatsächlich ändert variabel sein (benutzerdefinierte Schlüssel denken)

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class SinglePressKeyBinding { 

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

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

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

    public class TestPane extends JPanel { 

     private JLabel message; 

     private boolean spacedOut = false; 

     public TestPane() { 
      message = new JLabel("Waiting"); 
      setLayout(new GridBagLayout()); 
      add(message); 

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

      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "space-pressed"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "space-released"); 

      am.put("space-pressed", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        if (spacedOut) { 
         message.setText("I'm ignoring you"); 
        } else { 
         spacedOut = true; 
         message.setText("Spaced out"); 
        } 
       } 
      }); 
      am.put("space-released", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        spacedOut = false; 
        message.setText("Back to earth"); 
       } 
      }); 

     } 

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

    } 
} 
+0

Ich hatte ursprünglich eine Antwort auf Key Bindings, aber nach ein paar Tests fand ich, dass sie immer noch das gleiche Stottern Problem hatten. +1 für das andere Zeug jedoch. – syb0rg

+0

@ syb0rg Deshalb brauchen Sie diese kleine Fahne;). Das letzte Beispiel zeigt eine nette Idee, einem Schlüsselereignis zu erlauben, ein Beschleunigungsdelta anzuwenden, je länger es gedrückt wird, je mehr das Delta erhöht wird, bis es freigegeben wird und das Delta umgekehrt wird, verlangsamt sich das Objekt im Laufe der Zeit;) – MadProgrammer

+1

@ syb0rg Hinzugefügt ein einfaches Beispiel, um das Prinzip zu demonstrieren;) – MadProgrammer

7

ich ursprünglich eine Antwort über Key Bindings hatte, aber nach einer kleinen Prüfung fand ich, dass sie hatten immer noch die gleiche Stottern Problem.

Verlassen Sie sich nicht auf die Wiederholungsrate des Betriebssystems. Es kann für jede Plattform anders sein und ein Benutzer kann sie auch anpassen.

Verwenden Sie stattdessen einen Timer, um das Ereignis zu planen. Sie starten den Timer auf einem keyPressed und stoppen den Timer on keyReleased.

import java.awt.*; 
import java.awt.event.*; 
import java.net.*; 
import java.util.Map; 
import java.util.HashMap; 
import javax.imageio.ImageIO; 
import javax.swing.*; 

public class KeyboardAnimation implements ActionListener 
{ 
    private final static String PRESSED = "pressed "; 
    private final static String RELEASED = "released "; 
    private final static Point RELEASED_POINT = new Point(0, 0); 

    private JComponent component; 
    private Timer timer; 
    private Map<String, Point> pressedKeys = new HashMap<String, Point>(); 

    public KeyboardAnimation(JComponent component, int delay) 
    { 
     this.component = component; 

     timer = new Timer(delay, this); 
     timer.setInitialDelay(0); 
    } 

    public void addAction(String keyStroke, int deltaX, int deltaY) 
    { 
//  InputMap inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); 
     InputMap inputMap = component.getInputMap(); 
     ActionMap actionMap = component.getActionMap(); 

     String pressedKey = PRESSED + keyStroke; 
     KeyStroke pressedKeyStroke = KeyStroke.getKeyStroke(pressedKey); 
     Action pressedAction = new AnimationAction(keyStroke, new Point(deltaX, deltaY)); 
     inputMap.put(pressedKeyStroke, pressedKey); 
     actionMap.put(pressedKey, pressedAction); 

     String releasedKey = RELEASED + keyStroke; 
     KeyStroke releasedKeyStroke = KeyStroke.getKeyStroke(releasedKey); 
     Action releasedAction = new AnimationAction(keyStroke, RELEASED_POINT); 
     inputMap.put(releasedKeyStroke, releasedKey); 
     actionMap.put(releasedKey, releasedAction); 
    } 

    private void handleKeyEvent(String keyStroke, Point moveDelta) 
    { 
     // Keep track of which keys are pressed 

     if (RELEASED_POINT == moveDelta) 
      pressedKeys.remove(keyStroke); 
     else 
      pressedKeys.put(keyStroke, moveDelta); 

     // Start the Timer when the first key is pressed 

     if (pressedKeys.size() == 1) 
     { 
      timer.start(); 
     } 

     // Stop the Timer when all keys have been released 

     if (pressedKeys.size() == 0) 
     { 
      timer.stop(); 
     } 
    } 

    // Invoked when the Timer fires 

    public void actionPerformed(ActionEvent e) 
    { 
     moveComponent(); 
    } 

    // Move the component to its new location 

    private void moveComponent() 
    { 
     int componentWidth = component.getSize().width; 
     int componentHeight = component.getSize().height; 

     Dimension parentSize = component.getParent().getSize(); 
     int parentWidth = parentSize.width; 
     int parentHeight = parentSize.height; 

     // Calculate new move 

     int deltaX = 0; 
     int deltaY = 0; 

     for (Point delta : pressedKeys.values()) 
     { 
      deltaX += delta.x; 
      deltaY += delta.y; 
     } 


     // Determine next X position 

     int nextX = Math.max(component.getLocation().x + deltaX, 0); 

     if (nextX + componentWidth > parentWidth) 
     { 
      nextX = parentWidth - componentWidth; 
     } 

     // Determine next Y position 

     int nextY = Math.max(component.getLocation().y + deltaY, 0); 

     if (nextY + componentHeight > parentHeight) 
     { 
      nextY = parentHeight - componentHeight; 
     } 

     // Move the component 

     component.setLocation(nextX, nextY); 
    } 

    private class AnimationAction extends AbstractAction implements ActionListener 
    { 
     private Point moveDelta; 

     public AnimationAction(String keyStroke, Point moveDelta) 
     { 
      super(PRESSED + keyStroke); 
      putValue(ACTION_COMMAND_KEY, keyStroke); 

      this.moveDelta = moveDelta; 
     } 

     public void actionPerformed(ActionEvent e) 
     { 
      handleKeyEvent((String)getValue(ACTION_COMMAND_KEY), moveDelta); 
     } 
    } 

    public static void main(String[] args) 
    { 
     JPanel contentPane = new JPanel(); 
     contentPane.setLayout(null); 

     Icon dukeIcon = null; 

     try 
     { 
      dukeIcon = new ImageIcon("dukewavered.gif"); 
//   dukeIcon = new ImageIcon(ImageIO.read(new URL("http://duke.kenai.com/iconSized/duke4.gif"))); 
     } 
     catch(Exception e) 
     { 
      System.out.println(e); 
     } 

     JLabel duke = new JLabel(dukeIcon); 
     duke.setSize(duke.getPreferredSize()); 
     duke.setLocation(100, 100); 
     contentPane.add(duke); 

     KeyboardAnimation navigation = new KeyboardAnimation(duke, 24); 
     navigation.addAction("LEFT", -3, 0); 
     navigation.addAction("RIGHT", 3, 0); 
     navigation.addAction("UP", 0, -3); 
     navigation.addAction("DOWN", 0, 3); 

     navigation.addAction("A", -5, 0); 
     navigation.addAction("S", 5, 0); 
     navigation.addAction("Z", 0, -5); 
     navigation.addAction("X", 0, 5); 
     navigation.addAction("V", 5, 5); 

     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
//  frame.getContentPane().add(new JTextField(), BorderLayout.SOUTH); 
     frame.getContentPane().add(contentPane); 
     frame.setSize(600, 600); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

} 

Dieser Code wurde unter Windows getestet, wo die Reihenfolge der Ereignisse keyPressed ist, keyPressed, keyPressed ... keyReleased.

Aber ich denke, auf einem Mac (oder Unix) die Reihenfolge der Ereignisse ist keyPressed, keyReleased, keyPressed, keyReleased ... Also ich bin nicht sicher, ob dieser Code würde funktioniert besser als Ihre aktuellen Code.

+0

Nur zur Info, das Zitat stammt von mir, aber ich bin nicht das OP. – syb0rg

1

Eine gute Idee ist es, boolesche Werte für die zu verzeichnenden Schlüssel zu setzen, und dann auf dem keypressed-Ereignis einen der booleschen Werte zu aktivieren, und bei freigegebener Taste, diesen zu deaktivieren. Es wird die Verzögerung der Tasten entfernen und mehrere Tasten gleichzeitig drücken!

Verwandte Themen