Java-Gaming.org Java4K winners: [ by our judges | by the community ]         
Featured games (67)
games approved by the League of Dukes
Games in Showcase (∞)
games submitted by our members



News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  Print  
  Key handling  (Read 942 times)
0 Members and 1 Guest are viewing this topic.
Offline pjt33

JGO Strike Force
***

Posts: 913
Medals: 17



« on: 2009-01-21 13:04:40 »

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
{
   // Constants. You can make this slightly larger if it will compress better, but making it
  // smaller risks ArrayIndexOutOfBoundsExceptions in the event thread unless you add
  // bounds testing to processKeyEvent(...).
  private static final int NUM_KEYS = 0x10000;

   // Shared state. In the spirit of lock-free synchronisation, this is written
  // only by the event thread, and it advances values rather than setting /
  // resetting.
  private int[] keyEventCount = new int[NUM_KEYS];

   // This can be adapted if you do stuff properly rather than hackily, or if you use a JFrame
  @Override
   public void start()
   {
      // Set up event handling. Note: keyDown[key] and keyPressed[key] are 0
     // for false; any other value should be interpreted as true.
     enableEvents(KeyEvent.KEY_EVENT_MASK);
      int[] prevKeyEventCounts = new int[NUM_KEYS];
      int[] keyDown = new int[NUM_KEYS];
      int[] keyPressed = new int[NUM_KEYS];

      // Other setup...

      // Main game loop. Against, adapt as necessary.
     while (isActive())
      {
         // Handle events.
        for (int i = 0; i < NUM_KEYS; i++)
         {
            int eventCount = keyEventCount[i];
            // An odd number of events means that it's down. Simple!
           keyDown[i] = eventCount & 1;
            // The key was pressed since the last loop if the number of events
           // since then is at least two, by the pigeonhole principle, or if
           // the number of events since then is positive and the key is down.
           // Since we only need to catch the second case when delta == 1,
           // we can simplify the key-is-down test a bit.
           int delta = eventCount - prevKeyEventCounts[i];
            keyPressed[i] = (delta / 2) + (delta & eventCount);
            prevKeyEventCounts[i] = eventCount;
         }

         // Do game logic...
        // Render...
        // Sleep...
     }
   }

   @Override
   public void processKeyEvent(KeyEvent evt)
   {
      // The valid key event ids are 400, 401, 402.
     // Of those we care about 401 (KEY_PRESSED) and 402 (KEY_RELEASED).
     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.
Offline BitDragon

Jr. Member
**

Posts: 66


Sunset? Nice gradient paint!


« Reply #1 on: 2009-01-24 05:02:58 »

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.

I prefer keeping things simple. I use a key state array, but it is int, not boolean, and pressed keys set the int value of 1. This way, I can immediately use pressed key values in computations, e.g. (in pseudocode)

1  
rotation+=keystate[KEY_LEFT]*somevalue


To handle typed keys, I store the keycode of the most recently typed key in array entry 0 and I process this entry in the game loop, and reset it's value to 0, if its non-0.

hth Wolfgang

"I'm a ****ing starship, I'm allowed to cheat!"
GCU Arbitrary, Culture Craft
Pages: [1]
  Print  
 
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.16 | SMF © 2011, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.1 seconds with 22 queries.