4

I have a class calledActivity which extends JPanel

My problem is that I want the Activity to run the game loop (update its fields and GUI and etc) every 1000ms, but to always be checking for (in order to respond to) key presses.

private final BitSet keys = new BitSet(256);
...

public void keyPressed(final KeyEvent e) {
    keys.set(e.getKeyCode()); 
}

public void keyReleased(final KeyEvent e) {
    keys.clear(e.getKeyCode());
}

...

public void actionPerformed(ActionEvent e) {
  processKeys(); // Checks keys
  processData(); // Main game loop
  repaint();     // Draws game components
}

Presently, the class stores key presses in a BitSetand every 1000ms, actionPerformed() looks at the pressed keys (like moving player position to the right of right arrow is pressed), handles main game loop stuff (like ending the game if a boundary is hit), and repaints the screen, in that order.

The issue is that I have to press a key right before the timer fires in order for it to be detected, since otherwise it'll be deleted from the BitSet by the time processKeys() is called. I still want the game loop to run every 1000ms however.

I've considered either

  1. Creating 2 simultaneous timers -- 1000ms for the game loop, 1ms for key press analysis
  2. Setting the timer I have to 1ms, and using a class field to track timer fires. Check key presses every fire, and only run game loop/repaint when fires % 1000 == 0

I am not sure if #1 creates performance issues or leads to timer discrepancies, and I am pretty sure #2 is unreliable since when I've tried it, often the field never hit 1000 or 2000 or etc exactly.

What is the solution?

Kartik Chugh
  • 1,104
  • 14
  • 28

1 Answers1

3

As you seem to have discovered, since the delay between when the key is pressed and when you process it is so long, it's possible for the key to be removed from your BitSet before they are processed.

Instead, have two BitSets, one for pressed and one for released keys, after you've processed the keys, remove all the items in the "released keys" set from the "pressed keys" set, reset the "release keys" set and continue.

This, of course, assumes you want to process ANY key typed during the 1 second delay between process loops.

The other choice might be to actually process the key events in real time, applying their effects to some kind "change state" which can be applied to the actually model when the process loop occurs, but amounts to the same thing

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thanks for the answer. I'll try out the first option you listed. As for the second option, I used to do that, but as per the [answer here](http://stackoverflow.com/questions/11851155/handle-multiple-key-presses-ignoring-repeated-key/11851437#11851437) and the one below it, I was under the impression it was a bad event handling practice. So it's not really the "same thing", right? – Kartik Chugh Mar 23 '17 at 12:15