I'm more-or-less done with my first game and I'm thinking about a second. This would use keys, and I want to ensure that the key handling code is thread-safe. The topic of handling keys is discussed a bit in the tips thread, but I don't want to pollute that one, hence this thread. It might be appropriate to link to this thread, or a post in it, from that one once the dust settles.
The issue I have is this: the standard key handling discussed there is basically to detect key pressed and released events and update a boolean. That's fine if my game logic only cares whether keys are up or down, but not so fine if I care about detecting key presses: e.g. for jumping. If the pressed and released events both occur before the logic call then the character won't jump and may meet a frustrating doom.
My idea for approaching this is to borrow a trick from lock-free synchronisation (e.g. lock-free single-producer single-consumer, which is essentially what we have here: an event thread which produces events and another thread which does updates and probably renders). I would be grateful for critiques and improvements on this implementation, and suggestions of cheaper ways to obtain the same result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| public class Game4k extends Applet { private static final int NUM_KEYS = 0x10000;
private int[] keyEventCount = new int[NUM_KEYS];
@Override public void start() { enableEvents(KeyEvent.KEY_EVENT_MASK); int[] prevKeyEventCounts = new int[NUM_KEYS]; int[] keyDown = new int[NUM_KEYS]; int[] keyPressed = new int[NUM_KEYS];
while (isActive()) { for (int i = 0; i < NUM_KEYS; i++) { int eventCount = keyEventCount[i]; keyDown[i] = eventCount & 1; int delta = eventCount - prevKeyEventCounts[i]; keyPressed[i] = (delta / 2) + (delta & eventCount); prevKeyEventCounts[i] = eventCount; }
} }
@Override public void processKeyEvent(KeyEvent evt) { int id = evt.getID() & 3; if (id != 0) { keyEventCount[evt.getKeyCode()]++; } } } |
Ideally I'd like to debounce both keyDown and keyPressed as well, to work around the issue with some window managers (e.g. KDE) doing auto-repeat. However, there's no sure-fire way of telling whether multiple key presses come from the user or the WM, so I think I'll have to live with that issue.