2016-05-29 10 views
0

Ich versuche ein sehr einfaches Plattformspiel in Java zu schreiben. Ich hatte Teile davon mit passivem Rendering (mit einem Timer Objekt, das repaint() und revalidate() usw. aufruft), aber ich habe versucht, aktives Rendering zu implementieren. Es funktioniert irgendwie - in dem es rendert, und die Animation funktioniert, aber es scheint den Schlüssel Listener zu blockieren (was früher gut funktionierte) aus irgendeinem Grund, den ich nicht wirklich verstehe.Keylistener funktioniert nicht beim aktiven Rendern

Ich habe das Problem so wenig wie möglich nachgestellt. Wenn Sie eine Taste drücken, sollte die Ausgabe des Terminals erfolgen, aber es gibt keine. Wenn jemand mir erklären kann, warum die Methoden keyPressed etc. nicht feuern, würde es sehr geschätzt werden.

bearbeiten - Modifizierte Demo-Code in eine Kopieren/Einfügen als pro Anfrage

EDIT2 - Wie von Andrew Thompson vorgeschlagen, habe ich die ganzen Vollbild-Code entfernt und der keyListener immer noch nicht arbeiten

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import java.awt.*; 
import java.awt.event.KeyEvent; 
import java.awt.event.KeyListener; 
import java.awt.image.BufferStrategy; 

class FullScreenRenderWithListener implements KeyListener { 

    private JFrame frame; 
    private World world; 

    public static void main(String[] args) 
    { 
     FullScreenRenderWithListener main = new FullScreenRenderWithListener(); 
     SwingUtilities.invokeLater(main::run); 
    } 

    private void run() 
    { 
     initWindow(); 
     setupWorld(); 
     frame.setIgnoreRepaint(true); 
     frame.pack(); 
     frame.createBufferStrategy(2); 
     frame.setVisible(true); 
     world.startActive(frame.getBufferStrategy()); 
    } 

    private void initWindow() 
    { 
     frame = new JFrame(); 
     frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE); 
     frame.setLocationByPlatform(true); 
    } 

    private void setupWorld() 
    { 
     world = new World(); 
     frame.addKeyListener(this); 
     frame.add(world); 
     world.addKeyListener(this); 
    } 

    @Override 
    public void keyPressed(KeyEvent event) 
    { 
     System.out.println("Pressed"); 
    } 

    @Override 
    public void keyReleased(KeyEvent event) 
    { 
     System.out.println("Released"); 
    } 

    @Override 
    public void keyTyped(KeyEvent event) 
    { 
     System.out.println("Typed"); 
    } 
} 

class World extends JPanel { 

    private static final int FRAMES_PER_SEC = 60; 
    private static final int MILL_IN_SEC = 1000; 
    private static final int TICK_LENGTH = 
     MILL_IN_SEC/FRAMES_PER_SEC; 
    private BufferStrategy strategy; 

    private void sleepUntilEndOfFrame() 
    { 
     try { 
     long used = System.currentTimeMillis() % TICK_LENGTH; 
     long left = TICK_LENGTH - used; 
     Thread.sleep(left); 
     } catch(InterruptedException e) { 
     // ... Handle this error 
     } 
    } 

    public void startActive(BufferStrategy strategy) 
    { 
     this.strategy = strategy; 
     setIgnoreRepaint(true); 
     while(true) { 
     doFrame(); 
     } 
    } 

    private void doFrame() 
    { 
     updateGameState(); 
     activeRenderFrame(); 
    } 

    private void updateGameState() 
    { 
     // .. 
    } 

    private void activeRenderFrame() 
    { 
     Graphics2D graphicsContext = (Graphics2D)strategy 
     .getDrawGraphics(); 
     paintComponent(graphicsContext); 
     strategy.show(); 
     Toolkit.getDefaultToolkit().sync(); 
     graphicsContext.dispose(); 
     sleepUntilEndOfFrame(); 
    } 

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


    // Have overridden this method because the class 
    // also implements passive rendering if active is 
    // not supported 
    @Override 
    public void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 
     // .. drawing code 
    } 
} 
+0

Der Key Listener scheint dem Frame hinzugefügt zu sein. Wenn ein Rahmen zum Rahmen hinzugefügt wird, deckt er ihn vollständig ab und schluckt die Schlüsselereignisse. Aber ich kann nicht sehen, wie der ursprüngliche Rahmen wichtige Ereignisse erhalten hat, da er nicht fokussierbar war. Für weitere Hilfe, drehen Sie die beiden Codebeispiele in eine Kopie/Paste und geben Sie der 'Main' Klasse einen vernünftigen Namen, damit ich es in mein 'Junk-Code'-Paket zum Testen fallen lassen kann. –

+0

@AndrewThompson Fertig –

+0

Haben Sie versucht, die kompilieren Einzelkopie/Paste? Und 'Demo'? O_o Wie wäre es mit etwas Spezifischerem, das wahrscheinlich von jemand anderem mit einem Problem nicht benutzt wird: z.B. 'FullScreenRenderWithKeyListener'? –

Antwort

1

Das erste Problem ist nicht KeyBinding Strategie statt KeyListener speziell zu prüfen, zu verwenden, wenn Sie mit JPanel arbeiten. Sie können dies überprüfen, indem Sie die unendliche while-Schleife kommentieren (das aktive Rendering wird deaktiviert).

Wenn Sie KeyListener verwenden, wird kein KeyEvent ausgelöst (oder zumindest können wir sagen, dass unser Listener nicht aufgerufen wird), entweder mit aktivem Rendering-Prozess oder nicht.

Mit keyBinding wird dieses Problem behoben.

Aber wenn Sie die unendliche while Schleife auskommentieren, wird das Problem weiterhin angezeigt. Also, was kann dieses Problem lösen? Eine neue Thread zum Aktualisieren des Rahmens ist der Schlüssel!

Ihr Programm überprüfen, die von KeyBinding und einem neuen Thread für die Aktualisierung der Rahmen mit aktiven Rendering-Strategie verstärkt wird:

import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.Toolkit; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import java.awt.image.BufferStrategy; 
import java.util.HashMap; 
import java.util.Map; 

import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 
import javax.swing.SwingUtilities; 

public class FullScreenRenderWithListener implements Runnable 
{ 

    private JFrame frame; 
    private World world; 

    public static void main (String[] args) 
    { 
     FullScreenRenderWithListener main = new FullScreenRenderWithListener(); 
     SwingUtilities.invokeLater (main); 
    } 

    public void run() 
    { 
     initWindow(); 
     setupWorld(); 
     frame.setIgnoreRepaint (true); 
     frame.pack(); 
     frame.createBufferStrategy (2); 
     frame.setVisible (true); 
     world.startActive (frame.getBufferStrategy()); 
    } 

    private void initWindow() 
    { 
     frame = new JFrame(); 
     frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); 
     frame.setLocationByPlatform (true); 
    } 

    private void setupWorld() 
    { 
     world = new World(); 
     frame.add (world); 
     frame.setFocusable (true); 
     world.setFocusable (true); 
    } 
} 

class World extends JPanel 
{ 

    private static final int FRAMES_PER_SEC = 10; 
    private static final int MILL_IN_SEC = 1000; 
    private static final int TICK_LENGTH = MILL_IN_SEC/FRAMES_PER_SEC; 
    private BufferStrategy strategy; 
    // 
    private static final String PRESSED = "Pressed"; 
    private static final String RELEASED = "Released"; 
    private Map < Direction , Boolean > directionMap = new HashMap < Direction , Boolean >(); 

    private void sleepUntilEndOfFrame() 
    { 
     try 
     { 
      long used = System.currentTimeMillis() % TICK_LENGTH; 
      long left = TICK_LENGTH - used; 
      Thread.sleep (left); 
     } 
     catch (InterruptedException e) 
     { 
      // ... Handle this error 
      e.printStackTrace(); 
     } 
    } 

    private void setBindings() { 
      int context = JComponent.WHEN_IN_FOCUSED_WINDOW; 
      InputMap inputMap = getInputMap(context); 
      ActionMap actionMap = getActionMap(); 

      for (Direction direction : Direction.values()) { 
      inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, false), direction.getName() + PRESSED); 
      inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, true), direction.getName() + RELEASED); 

      // set corresponding actions for the key presses and releases above 
      actionMap.put(direction.getName() + PRESSED, new ArrowKeyAction(true, direction)); 
      actionMap.put(direction.getName() + RELEASED, new ArrowKeyAction(false, direction)); 
      } 
    } 

    public void startActive (BufferStrategy strategy) 
    { 
     for (Direction direction : Direction.values()) 
     { 
      directionMap.put (direction , Boolean.FALSE); 
     } 
     setBindings(); 
     // 
     this.strategy = strategy; 
     setIgnoreRepaint (true); 
     Thread t = new Thread(){ 
      @Override 
      public void run() 
      { 
       while (true) 
       { 
        doFrame(); 
       } 
      } 
     }; 
     t.start(); 
    } 

    private void doFrame() 
    { 
     updateGameState(); 
     activeRenderFrame(); 
    } 

    private void updateGameState() 
    { 
     // .. 
    } 

    private void activeRenderFrame() 
    { 
     Graphics2D graphicsContext = (Graphics2D) strategy.getDrawGraphics(); 
     paintComponent (graphicsContext); 
     strategy.show(); 
     Toolkit.getDefaultToolkit().sync(); 
     graphicsContext.dispose(); 
     sleepUntilEndOfFrame(); 
    } 

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

    // Have overridden this method because the class 
    // also implements passive rendering if active is 
    // not supported 
    @Override 
    public void paintComponent (Graphics g) 
    { 
     super.paintComponent (g); 
     // .. drawing code 
    } 

    private class ArrowKeyAction extends AbstractAction 
    { 
     private Boolean pressed; 
     private Direction direction; 

     public ArrowKeyAction (boolean pressed , Direction direction) 
     { 
      this.pressed = Boolean.valueOf (pressed); 
      this.direction = direction; 
     } 

     @Override 
     public void actionPerformed (ActionEvent arg0) 
     { 
      directionMap.put (direction , pressed); 
      System.out.println ("Direction: "+ direction + ", State: " + pressed); 
     } 
    } 
} 

enum Direction { 
    UP("Up", KeyEvent.VK_UP, new Point(0, -1)), 
    DOWN("Down", KeyEvent.VK_DOWN, new Point(0, 1)), 
    LEFT("Left", KeyEvent.VK_LEFT, new Point(-1, 0)), 
    Right("Right", KeyEvent.VK_RIGHT, new Point(1, 0)); 

    private String name; 
    private int keyCode; 
    private Point vector; 
    private Direction(String name, int keyCode, Point vector) { 
     this.name = name; 
     this.keyCode = keyCode; 
     this.vector = vector; 
    } 
    public String getName() { 
     return name; 
    } 
    public int getKeyCode() { 
     return keyCode; 
    } 
    public Point getVector() { 
     return vector; 
    } 
    @Override 
    public String toString() { 
     return name; 
    } 
} 

Diese Probe bindet nur einige KeyBinding für die Pfeiltasten. Sie können auch andere Schlüssel auschecken, indem Sie die Methode ändern. Sie können auch weitere Event s und andere enum für andere Schlüssel definieren.

Hoffe, das hilft.

+0

Danke! Das sieht so aus als wäre es der Typ ... Ich werde morgen die Lösung ausprobieren. –

+0

@BenWainwright: Wäre froh, wenn das hilft ;-) – STaefi

+0

mein Laptop ist kaputt, also kann ich nicht arbeiten, bis ich wieder in uni bin, was in einer Stunde oder so sein wird –

Verwandte Themen