Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (475)
Games in Android Showcase (106)
games submitted by our members
Games in WIP (530)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Keyboard Mapping  (Read 1067 times)
0 Members and 1 Guest are viewing this topic.
Offline Troncoso

JGO Coder


Medals: 20



« Posted 2012-10-26 03:33:13 »

I may be doing this in a completely horrible way, but my idea for my game engine is to create a list that a user can add a KeyMap object to. So, I have a KeyMap class and a KeyMaps class, as shown:
KeyMap
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
public class KeyMap implements KeyListener 
{
   public void keyPressed(KeyEvent arg0) {}

   public void keyReleased(KeyEvent arg0) {}

   public void keyTyped(KeyEvent arg0) {}
   
   
}


KeyMaps
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 KeyMaps extends JComponent 
{

   // Contains this object
  private static KeyMaps listOfKeyMaps;
   
   // Contains a list of KeyMap objects linked by a
  // KeyMap title
  private HashMap<String, KeyMap> keyMaps;
   
   // Contains the current KeyMap to use
  private KeyMap activeKeyMap;
   
   private KeyMaps()
   {
      keyMaps = new HashMap<String, KeyMap>();
      activeKeyMap = new SystemKeyMap();
      addKeyMap ("System", activeKeyMap);
      setActiveKeyMap ("System");
   }
   
   public static KeyMaps getInstance()
   {
      if (listOfKeyMaps == null) {
         synchronized (KeyMap.class) {
            if (listOfKeyMaps == null)
               listOfKeyMaps = new KeyMaps();
         }
      }
     
      return listOfKeyMaps;
   }
   
   public void setActiveKeyMap(String newKeyMap)
   {
      if (keyMaps.containsKey(newKeyMap)) {
         removeKeyListener (activeKeyMap);
         activeKeyMap = keyMaps.get (newKeyMap);
         addKeyListener (activeKeyMap);
      }
   }
   
   public boolean addKeyMap(String keymapName, KeyMap km)
   {
      if (keyMaps.containsKey (keymapName))
         return false;
      else {
         keyMaps.put (keymapName, km);
         return true;
      }
   }
   
   public boolean removeKeymap(String keymapName)
   {
      if (keyMaps.containsKey (keymapName))
         return false;
      else {
         keyMaps.remove (keymapName);
         return true;
      }
   }
}


As you can see, my idea is for the user to be able to create a set of KeyListeners to handle KeyEvents. The KeyMaps class would hold this list while maintaining a single active KeyMap, and the ability to easily switch between them (So, you can have a different KeyMap for gameplay, the main menu, mini-games, etc.) My issue is that, I don't think this works for a reason I'm not aware of. I created a simple KeyMap that exits the program if the use presses esc:

1  
2  
3  
4  
5  
6  
7  
public class SystemKeyMap extends KeyMap
{
   public void keyReleased(KeyEvent ke) {
      if (ke.getKeyCode() == KeyEvent.VK_ESCAPE)
         System.exit (0);
   }
}


You can see in the KeyMaps class that this is automatically created and activated upon starting the program. This is how I've implemented it into the actual game:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
public abstract class Game
{

   // The game window
  private Screen screen;
   
   // The container for all graphics
  private Canvas canvas;
   
   // Contains a list of KeyMaps
  private KeyMaps keymaps;
   
   /**
    * Initializes the game window
    */

   public Game()
   {
      super();
      screen = new Screen();
      canvas = new Canvas();
      screen.add (canvas);
     
      keymaps = KeyMaps.getInstance();
   }


Nothing happens when I press the ESC button. Could I get some insight on why that is?
Offline Ultroman

JGO Knight


Medals: 24
Projects: 1


Snappin' at snizzes since '83


« Reply #1 - Posted 2012-10-26 04:38:27 »

You need to do this after instantiating your KeyMap:
1  
canvas.addKeyListener(keymaps.getActiveKeyMap());


EDITED: It's a bit of a weird build you've done, and you'll have to keep changing the keymap associated with your canvas, but that should work, assuming you make a getter for the currently active keymap.

- Jonas
Offline Troncoso

JGO Coder


Medals: 20



« Reply #2 - Posted 2012-10-26 04:52:00 »

Thanks for the reply!

Your solution worked, though, I needed to add the listener to the screen, not the canvas. Though, that is trivial.
So, is there not a way to add the listeners to the KeyMaps object? Like my code shows? Or is it necessary that the Screen object have it? Due to the focus, I suppose.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline SHC
« Reply #3 - Posted 2012-10-26 05:03:26 »

Here's a simple Keyboard class

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  
public class Keyboard implements KeyListener {

    private static HashMap<Integer, Boolean> keyPresses = new HashMap<Integer, Boolean>();
    private static HashMap<Integer, Boolean> keyReleases = new HashMap<Integer, Boolean>();

    public void keyPressed(KeyEvent e){
        keyPresses.put(e.getKeyCode(), true);
        keyReleases.put(e.getKeyCode(), false);
    }

    public void keyReleased(KeyEvent e){
        keyReleases.put(e.getKeyCode(), true);
    }

    public void keyTyped(KeyEvent e){}

    public static boolean isPressed(int keyCode, boolean initialPress){
        if (keyPresses.containsKey(keyCode)){
            boolean bool = keyPresses.get(keyCode);
            if (initialPress){
                bool = bool && !keyReleases.get(keyCode);
                keyPresses.put(keyCode, false);
            }
            return bool;
        }
        return false;
    }

}


See https://code.google.com/p/game-engine-for-java/source/browse/#git%2Fsrc%2Fcom%2Fgej%2Finput for the classes I use in my engine.

Offline Ultroman

JGO Knight


Medals: 24
Projects: 1


Snappin' at snizzes since '83


« Reply #4 - Posted 2012-10-26 05:11:25 »

Exactly, the focus is controlled by the actual "surface" you're using, and it is the KeyListener on that, which is activated.

EDIT2: Wow, now I read it again. You're assigning a new KeyListener for each key you want bound, if I'm reading this correctly. You shouldn't do that. A KeyListener can report to you which keys are pressed on the entire keyboard, not just for a single key.

Check this and the 2 next videos out. He explains it quite slowly, and the videos can't be followed as such because they assume you've followed the 27 preceeding videos, but just looking at what he does, should get you the right idea about how this works.
Key elements are:
- He has a class that implements the KeyListener.
- He makes an instance of this class, and sets it to be the KeyListener on his canvas, window or frame, depending on what you're doing.
- Then he can use his KeyListener class to check whether some key is down
- You should not have your game-class implement KeyListener like he does in this example. You can, but it is easier to abstract it from the code.

I did it like this in my first game, where my Game-class implemented KeyListener:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
if(mainPlayerMenu!=null){
   if(abilitiesPanel!=null){
      if(keys[KeyEvent.VK_UP] && playerActivationDelay == 0){
         playerActivationDelay = 12;
         abilitiesPanel.moveUpThroughChoices();
      }
      if(keys[KeyEvent.VK_DOWN] && playerActivationDelay == 0){
         playerActivationDelay = 12;
         abilitiesPanel.moveDownThroughChoices();
      }
}


This is obviously very ugly, so for the next game, I made a class like this:
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  
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class KeyboardController implements KeyListener {
    private boolean[] keys;

    public KeyboardController(boolean[] keys) {
               this.keys = keys;
    }

    public void keyPressed(KeyEvent e) {
      int status = e.getID(), key = e.getKeyCode();
      if(status == KeyEvent.KEY_PRESSED) {
         if(!keys[key]){
            System.out.println(""+KeyEvent.getKeyText(key));
            keys[key] = true;
         }
      }
      e.consume();
    }

    public void keyReleased(KeyEvent e) {
       int status = e.getID(), key = e.getKeyCode();
      if(status == KeyEvent.KEY_RELEASED) {
         keys[key] = false;
      }
      e.consume();
    }

   @Override
   public void keyTyped(KeyEvent e) {
      e.consume();
   }
}


The code in my Game-class becomes something like this:
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  
private boolean[] keys = new boolean[256];
private KeyboardController kc;
private int downKey, leftKey, rightKey, jumpKey, ammoKey, switchKey, reloadKey, shootKey, meleeKey;

...

// in init(), I do this
kc = new KeyboardController(keys);

//      initialize controls from player settings
     leftKey = playerSettings.getKeys().get("Left");
      rightKey = playerSettings.getKeys().get("Right");
      downKey = playerSettings.getKeys().get("Down");
      jumpKey = playerSettings.getKeys().get("Jump");
      ammoKey = playerSettings.getKeys().get("ChangeAmmo");
      switchKey = playerSettings.getKeys().get("ChangeWeapon");
      reloadKey = playerSettings.getKeys().get("Reload");
      shootKey = playerSettings.getKeys().get("Shoot");
      meleeKey = playerSettings.getKeys().get("Melee");

...

           w.addKeyListener(kc);
      w.setFocusTraversalKeysEnabled(false);

// then I have a method called actuateControls() which I call every game-update,
// which does something like this, depending on which state it is in at the time

private void actuateControls() {
      if(state==GAME){
         if(keys[shootKey]){
            game.shoot();
         }
         if(keys[KeyEvent.VK_ESCAPE]){
            stop();
         }
//         ............blablabla
     }else if(state == MENU)
//         ............blablabla

}

- Jonas
Offline Ultroman

JGO Knight


Medals: 24
Projects: 1


Snappin' at snizzes since '83


« Reply #5 - Posted 2012-10-26 05:18:25 »

SHC's listener is very nice too. I just never had the need to know when something was released; only if it is currently pressed.

- Jonas
Offline Troncoso

JGO Coder


Medals: 20



« Reply #6 - Posted 2012-10-26 06:53:26 »

Exactly, the focus is controlled by the actual "surface" you're using, and it is the KeyListener on that, which is activated.

EDIT2: Wow, now I read it again. You're assigning a new KeyListener for each key you want bound, if I'm reading this correctly. You shouldn't do that. A KeyListener can report to you which keys are pressed on the entire keyboard, not just for a single key.

That's not correct. Each KeyMap is designed to layout the functionality of the entire keyboard. The reason for a list of them is to easily switch between interfaces while changing what the keys do. Like in my example before, you could have your keys mapped for the game play, and then have a different mapping for when you are navigating menus. Stuff like that.

I'm trying to design the engine in a way where that option is available, but not necessary. Like, the SysemKeyMap that is applied by default could be overwritten and used as the only Listener for the whole game.
Offline Ultroman

JGO Knight


Medals: 24
Projects: 1


Snappin' at snizzes since '83


« Reply #7 - Posted 2012-10-26 12:00:27 »

Exactly, the focus is controlled by the actual "surface" you're using, and it is the KeyListener on that, which is activated.

EDIT2: Wow, now I read it again. You're assigning a new KeyListener for each key you want bound, if I'm reading this correctly. You shouldn't do that. A KeyListener can report to you which keys are pressed on the entire keyboard, not just for a single key.

That's not correct. Each KeyMap is designed to layout the functionality of the entire keyboard. The reason for a list of them is to easily switch between interfaces while changing what the keys do. Like in my example before, you could have your keys mapped for the game play, and then have a different mapping for when you are navigating menus. Stuff like that.

I'm trying to design the engine in a way where that option is available, but not necessary. Like, the SysemKeyMap that is applied by default could be overwritten and used as the only Listener for the whole game.
I was hoping that was the case Smiley I really shouldn't read through other people's code at 5 in the morning ^^

- Jonas
Offline SHC
« Reply #8 - Posted 2012-10-26 15:29:51 »

If there is no need to check key releases, then the code is much more simplified.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public class Keyboard implements KeyListener {

    boolean[] keys = new boolean[600]; // 600 keys are defined in the KeyEvent

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

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

    public static boolean isPressed(int keyCode){
        return keys[keyCode];
    }

}

Offline Ultroman

JGO Knight


Medals: 24
Projects: 1


Snappin' at snizzes since '83


« Reply #9 - Posted 2012-10-26 15:59:35 »

You're right. Actually I don't see why I ever used the eventID. Must be a remnant of some system I used once.

I was told it was good practice to consume the KeyEvent once you had processed it, though. Is this false?

- Jonas
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Troncoso

JGO Coder


Medals: 20



« Reply #10 - Posted 2012-10-26 17:19:09 »

If there is no need to check key releases, then the code is much more simplified.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public class Keyboard implements KeyListener {

    boolean[] keys = new boolean[600]; // 600 keys are defined in the KeyEvent

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

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

    public static boolean isPressed(int keyCode){
        return keys[keyCode];
    }

}


That does seem a lot simpler. I know my implementation is kind of crude, as far as the actual key presses go. My main concern at the moment was properly implementing my KeyMapping system. Though, I'll likely be using this method for my actual KeyMap class. Thanks for that!
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

ctomni231 (36 views)
2014-07-18 06:55:21

Zero Volt (34 views)
2014-07-17 23:47:54

danieldean (27 views)
2014-07-17 23:41:23

MustardPeter (30 views)
2014-07-16 23:30:00

Cero (45 views)
2014-07-16 00:42:17

Riven (46 views)
2014-07-14 18:02:53

OpenGLShaders (35 views)
2014-07-14 16:23:47

Riven (35 views)
2014-07-14 11:51:35

quew8 (31 views)
2014-07-13 13:57:52

SHC (67 views)
2014-07-12 17:50:04
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!