2017-03-25 3 views
0

Je suis nouveau à la programmation java et j'ai commencé à programmer un jeu. J'ai un caractère qui bouge avec wasd mais trouve que lorsque:Les clés Java ne sont pas récupérées?

  1. Une touche de mouvement est enfoncée.
  2. Le JFrame a été déconnecté. (Donc, il devient flou.)
  3. La même clé est libérée.
  4. JFrame est à nouveau focalisé.

... que le jeu ne détectera pas que le joueur ne devrait pas bouger. J'ai donc essayé de le réparer en changeant tout le tableau keys false:

public class KeyManager implements KeyListener { 

private Game game; 

private boolean[] keys; 
public boolean up, down, left, right; //Player class reads these variables 

public KeyManager(Game game) { 
    this.game = game; 
    keys = new boolean[256]; 
} 

public void tick() { 
    if(!game.getDisplay().getFrame().isFocused()) { //Here is the problem 
     for(int i = 0; i < keys.length; i++) { 
      keys[i] = false; //Repeats 256 x 60 times a second 
     } 
    } 
    up = keys[KeyEvent.VK_W]; //I realize that I could just change 
    down = keys[KeyEvent.VK_S]; //up, down, left, right to false but 
    left = keys[KeyEvent.VK_A]; //when the JFrame is refocused the game 
    right = keys[KeyEvent.VK_D]; //still doesn't know the key was released 
} 

@Override 
public void keyPressed(KeyEvent e) { 
    keys[e.getKeyCode()] = true; 
} 

@Override 
public void keyReleased(KeyEvent e) { 
    keys[e.getKeyCode()] = false; 
} 

@Override 
public void keyTyped(KeyEvent e) { 

} 

} 

Il a travaillé, mais après avoir réfléchi sur le code, j'ai réalisé que depuis la méthode tick() est appelée 60 fois par seconde et le tableau de clés est de 256 clés de long qu'il met à jour 15 900 booléens clés toutes les secondes pour seulement 4 clés importantes qui doivent être changées en false.

Quel est le moyen le plus efficace de le faire? J'ai l'impression qu'il me manque quelque chose de vraiment simple.

+0

Cela peut être utile: http://rahalsblogs.blogspot.com/2015/08/how-to-use-keyeventdispatcher-with.html –

+0

Utilisez l'API clé bindings, au lieu de l'auditeur clé – MadProgrammer

+0

Ce que je " peut "faire est d'utiliser l'API de liaison de clés pour définir l'état des drapeaux" clés ", qui seraient alors indépendants de la boucle de jeu. J'utiliserais alors un 'FocusListener' sur le' JFrame' pour (éventuellement) mettre en pause le jeu et réinitialiser les drapeaux clés – MadProgrammer

Répondre

1

La première chose que je ferais, est d'utiliser le Key Bindings API au lieu d'un KeyListener. Je voudrais le mettre à jour les drapeaux principaux (personnellement, j'utiliserais un Set et un certain type de Inputenum, mais c'est moi) indépendamment de la "boucle de jeu".

je puis utiliser un FocusListener sur la JFrame et simplement mettre en pause/reprendre la « boucle de jeu » lorsque le focus est perdu/gagné, en option Remise à zéro des drapeaux clés

Quelque chose comme ça, par exemple ...

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.FocusEvent; 
import java.awt.event.FocusListener; 
import java.awt.event.KeyEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test { 

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

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

       JFrame frame = new JFrame("Testing"); 
       TestPane tp = new TestPane(); 
       frame.addFocusListener(new FocusListener() { 
        @Override 
        public void focusGained(FocusEvent e) { 
         tp.resume(); 
        } 

        @Override 
        public void focusLost(FocusEvent e) { 
         tp.pause(true); 
        } 
       }); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(tp); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private boolean aPressed = false; 
     private Timer timer; 

     public TestPane() { 
      InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW); 
      ActionMap actionMap = getActionMap(); 

      inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "A.pressed"); 
      inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "A.released"); 
      actionMap.put("A.pressed", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        aPressed = true; 
       } 
      }); 
      actionMap.put("A.released", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        aPressed = false; 
       } 
      }); 

      timer = new Timer(16, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        System.out.println("A pressed = " + aPressed); 
       } 
      }); 
     } 

     public void resume() { 
      timer.restart(); 
     } 

     public void pause(boolean reset) { 
      timer.stop(); 
      if (reset) { 
       aPressed = false; 
      } 
     } 

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

    } 

}