Reputation: 3
I'm new to java programming and have begun programming a game. I have a character that moves with wasd but found that when:
...that the game won't pick it up that the player shouldn't be moving. So I tried to fix it by changing all the keys array to 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) {
}
}
It worked, but after thinking over the code I realized that since the tick() method is called 60 times a second and the keys array is 256 keys long that it was updating 15,900 key booleans every second for only 4 important keys that needed to be changed to false.
What is the most efficient way to do this? I feel like I'm missing something really simple.
Upvotes: 0
Views: 93
Reputation: 347314
The first thing I would do, is use the Key Bindings API instead of a KeyListener
. I would have it update the key flags (personally, I'd use a Set
and some type of Input
enum
, but that's me) independently of the "game loop".
I would then use a FocusListener
on the JFrame
and simply pause/resume the "game loop" when focus is lost/gained, optionally resetting the key flags
Something like this, for example...
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);
}
}
}
Upvotes: 1