Results 1 to 16 of 16
  1. #1
    MagnusLarsen is offline Member
    Join Date
    Aug 2010
    Posts
    7
    Rep Power
    0

    Default Checking for multiple keys pressed

    so im very new to java, and i made a program where u can move a little block arround in a little world and "shoot" you move with "WASD" but the movement is very buggy, 1 very important thing is that i cant move 2 directions at the same time, i would like to be able to press both example: A and W and go that > \ way

    so here is part of my code:

    public void keyPressed( KeyEvent e ) {

    // was the easyest way for me to get the ascii of the charather pressed in an int
    keyI = e.getKeyCode() + 32;

    // speed = 3
    for(int i = 0; i < speed; i += 1){
    //W
    if (keyI == 119 && free(px, py - 1 - rectsize/2) == true){py -= 1;}
    //A
    if (keyI == 97 && free(px - 1 - rectsize/2, py ) == true){px -= 1;}
    //S
    if (keyI == 115 && free(px, py + 1 + rectsize/2) == true){py += 1;}
    //D
    if (keyI == 100 && free(px + 1 + rectsize/2, py ) == true){px += 1;}
    }

    repaint();
    }

    so anybody know a good way to make it detect if there is more than 1 key pressed at a time, and which ?

    im not sure if this is enough, just tell me if you need the whole code.
    Last edited by MagnusLarsen; 08-12-2010 at 07:57 PM.

  2. #2
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    13,655
    Blog Entries
    7
    Rep Power
    21

    Default

    You can't do that with just the keyPressed( ... ) method; you need at least one of the other (keyReleased( ... ) and keyTyped( ... )) methods. Read the API documentation for the KeyEvent class for quite a detailed description how and when those events are fired. It also depends on the 'n-key rollover' feature of the keyboard itself.

    kind regards,

    Jos
    Last edited by JosAH; 08-12-2010 at 08:36 PM.

  3. #3
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    Eastern Florida
    Posts
    17,562
    Rep Power
    25

    Default

    If you press and hold key A then press and hold key B while still holding key A you would have two keys pressed at the same time. Use the keyReleased listener method to know when the keys are released.

    The listeners would hear: KeyA pressed, KeyB pressed, ..... Key(AorB) released, Key(BorA) released.

    Your code would have to remember the state of the keys.

  4. #4
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    I would use key binding, not key listeners, and would create two separate actions for each key, one for press and one for release. I'd then use one boolean for each key to represent the state of the key: pressed or released. I'd then use a game timer to poll the set of booleans and move the sprite accordingly. For example, something like this:

    Java Code:
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.image.BufferedImage;
    import java.util.HashMap;
    import java.util.Map;
    import javax.swing.*;
    
    public class KeyBindingsGuiTest {
       private static void createAndShowUI() {
          KeyBindingsGui guiPanel = new KeyBindingsGui();
    
          JFrame frame = new JFrame("KeyBindingsGuiTest");
          frame.getContentPane().add(guiPanel);
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          java.awt.EventQueue.invokeLater(new Runnable() {
             public void run() {
                createAndShowUI();
             }
          });
       }
    }
    
    @SuppressWarnings("serial")
    class KeyBindingsGui extends JPanel {
       private static final Dimension SIZE = new Dimension(600, 600);
       private static final int SPRITE_WIDTH = 26;
       private static final int SPRITE_HEIGHT = SPRITE_WIDTH;
       private static final int STROKE_WIDTH = 3;
       private static final Color SPRITE_COLOR = Color.red;
       private static final Color GUI_BCKGRD = Color.white;
       private static final String PRESSED = "Pressed";
       private static final String RELEASED = "Released";
       public static final int SPRITE_STEP = 8;
       private static final int SPRITE_STEP_PERIOD = 20;
       private BufferedImage sprite;
       private int spriteX = 0;
       private int spriteY = 0;
       private Map<Direction, Boolean> directionMap = new HashMap<Direction, Boolean>();
       
       public KeyBindingsGui() {
          setBackground(GUI_BCKGRD);
          setPreferredSize(SIZE);
          sprite = createSprite();
          spriteX = (SIZE.width - SPRITE_WIDTH)/2; 
          spriteY = (SIZE.height - SPRITE_HEIGHT)/2;
          
          for (Direction direction : Direction.values()) {
             directionMap.put(direction, Boolean.FALSE);
          }
          
          setBindings();
          Timer timer = new Timer(SPRITE_STEP_PERIOD, new GameLoopListener());
          timer.start();
       }
       
       @Override
       protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          if (sprite != null) {
             g.drawImage(sprite, spriteX, spriteY, null);
          }
       }
    
       private void setBindings() {
          int context = JComponent.WHEN_IN_FOCUSED_WINDOW;
          InputMap inputMap = getInputMap(context);
          ActionMap actionMap = getActionMap();
    
          for (Direction direction : Direction.values()) {
             inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, false), 
                      direction.getName() + PRESSED);
             inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, true), 
                      direction.getName() + RELEASED);
    
             // set corresponding actions for the  key presses and releases above
             actionMap.put(direction.getName() + PRESSED, new ArrowKeyAction(true, direction));
             actionMap.put(direction.getName() + RELEASED, new ArrowKeyAction(false, direction));
          }
    
       }
    
       private BufferedImage createSprite() {
          BufferedImage sprite = new BufferedImage(SPRITE_WIDTH, SPRITE_HEIGHT,
                   BufferedImage.TYPE_INT_ARGB);
          Graphics2D g2d = sprite.createGraphics();
          g2d.setStroke(new BasicStroke(STROKE_WIDTH));
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
          g2d.setColor(SPRITE_COLOR);
          g2d.drawOval(STROKE_WIDTH, STROKE_WIDTH, SPRITE_WIDTH - 2 * STROKE_WIDTH, 
                   SPRITE_HEIGHT - 2 * STROKE_WIDTH);
          g2d.dispose();
          return sprite;
       }
       
       private class ArrowKeyAction extends AbstractAction {
          private Boolean pressed;
          private Direction direction;
          public ArrowKeyAction(boolean pressed, Direction direction) {
             this.pressed = Boolean.valueOf(pressed);
             this.direction = direction;
          }
    
          @Override
          public void actionPerformed(ActionEvent arg0) {
             directionMap.put(direction, pressed);
          }
       }
       
       private class GameLoopListener implements ActionListener {
          
          public void actionPerformed(ActionEvent e) {
             int x0 = spriteX;
             int y0 = spriteY;
             for (Direction direction : Direction.values()) {
                if (directionMap.get(direction)) {
                   spriteX += SPRITE_STEP * direction.getVector().x;
                   spriteY += SPRITE_STEP * direction.getVector().y;
                }
             }
             int x = Math.min(x0, spriteX);
             int y = Math.min(y0, spriteY);
             int w = Math.max(x0, spriteX) - x + SPRITE_WIDTH;
             int h = Math.max(y0, spriteY) - y + SPRITE_HEIGHT;
             repaint(x, y, w, h);
          }
       }
    }
    
    enum Direction {
       UP("Up", KeyEvent.VK_UP, new Point(0, -1)),
       DOWN("Down", KeyEvent.VK_DOWN, new Point(0, 1)),
       LEFT("Left", KeyEvent.VK_LEFT, new Point(-1, 0)),
       Right("Right", KeyEvent.VK_RIGHT, new Point(1, 0));
       
       private String name;
       private int keyCode;
       private Point vector;
       private Direction(String name, int keyCode, Point vector) {
          this.name = name;
          this.keyCode = keyCode;
          this.vector = vector;
       }
       public String getName() {
          return name;
       }
       public int getKeyCode() {
          return keyCode;
       }
       public Point getVector() {
          return vector;
       }
       @Override
       public String toString() {
          return name;
       }
    }

  5. #5
    MagnusLarsen is offline Member
    Join Date
    Aug 2010
    Posts
    7
    Rep Power
    0

    Default Thanks

    thx for the replyes, i made it work and could ( and should ) probally have figgured it out by myself

    heres what i changed it to, its still not perfect movement but it works fine :
    Java Code:
    public void keyPressed( KeyEvent e ) {
    	   keyI = e.getKeyCode() + 32;
    	   if (keyI == 119){ keyW = true; }
    	   if (keyI == 97){ keyA = true; }
    	   if (keyI == 115){ keyS = true; }
    	   if (keyI == 100){ keyD = true; }
    	   
    	   for(int i = 0; i < speed; i += 1){
    	   //W
    	   if (keyW == true && free(px, py - 1 - rectsize/2) == true){py -= 1;}
    	   //A
    	   if (keyA == true && free(px - 1 - rectsize/2, py ) == true){px -= 1;}
    	   //S
    	   if (keyS == true && free(px, py + 1 + rectsize/2) == true){py += 1;}
    	   //D
    	   if (keyD == true && free(px + 1 + rectsize/2, py ) == true){px += 1;}
    	   }
    	   
    	   repaint();
       }
       public void keyReleased( KeyEvent e ) {
    	   keyI = e.getKeyCode() + 32;
    	   if (keyI == 119){ keyW = false; }
    	   if (keyI == 97){ keyA = false; }
    	   if (keyI == 115){ keyS = false; }
    	   if (keyI == 100){ keyD = false; }
    	   
       }

  6. #6
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    Eastern Florida
    Posts
    17,562
    Rep Power
    25

    Default

    Why all the hardcoded decimal literals? what is a 119? Is that the same as 'w'?
    'w' is much easier to understand and you'll make fewer mistakes using the char literal than the decimal literal. What if you mistyped 199 or 191? You might not see it?

    Also in stead of using 'w' here and another 'w' there, create one final variable and use it in all the places you need to test for the letter w.
    final char MoveUpChar = 'w';

    If you decided to change the letters used to move the mouse, there would only be one set of variables to change, instead of dozens of decimal values like 119 etc

  7. #7
    MagnusLarsen is offline Member
    Join Date
    Aug 2010
    Posts
    7
    Rep Power
    0

    Default

    the reason im using 119 for 'w' is because its the ascii number for w, its what i get when i retrieve the key pressed, its easyest just to use it directly from there instead of then making it into a char or w/e

    when im learning a new language like java i just like to make the code as short as possible even though it might look messy and hard to understand

  8. #8
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    Eastern Florida
    Posts
    17,562
    Rep Power
    25

    Default

    like to make the code as short as possible
    It depends on if you expect to write production code. Good habits formed early will have you writing better code. Your code is not very maintainable with all the hardcode decimal constants. No one can look at the code and understand what 119 means without going to a table to see that its the value for 'w'.
    Plus a self documenting variable like "MoveUpChar"
    final char MoveUpChar = 'w';

    Makes the code easier for anyone to understand.

    When I taught programming and graded students code, usages like yours would merit -10 points for poor documenting and poor maintainability.

  9. #9
    MagnusLarsen is offline Member
    Join Date
    Aug 2010
    Posts
    7
    Rep Power
    0

    Default

    will consider using more variables instead of writing every number :)

    -10 for me on this on though

  10. #10
    mine0926 is offline Senior Member
    Join Date
    Apr 2010
    Location
    Philippines
    Posts
    580
    Rep Power
    5

    Default

    If I am in your case I will follow fubarable's advice and use KeyBinding instead of keylistener and create an event seperate event for keys "W", "A", "S", "D", "WA", "WD", "AS" and "DS". That will be a lot easier.

  11. #11
    MagnusLarsen is offline Member
    Join Date
    Aug 2010
    Posts
    7
    Rep Power
    0

    Default

    I will try to find a tutorial on how to use KeyBinding then :)

    ty

  12. #12
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

  13. #13
    MagnusLarsen is offline Member
    Join Date
    Aug 2010
    Posts
    7
    Rep Power
    0

    Default im lost

    think that was a step too big using KeyBindings, i dont understand half of what that page says, and i cant even get the code u posted working :(

    dunno what to do...

  14. #14
    cselic is offline Senior Member
    Join Date
    Apr 2010
    Location
    Belgrade, Serbia
    Posts
    278
    Rep Power
    5

    Default

    think that was a step too big using KeyBindings, i dont understand half of what that page says, and i cant even get the code u posted working
    If there is something that you don't understand on that page, or in Fubarable's example, you can ask us :cool:
    We will help you.

  15. #15
    MagnusLarsen is offline Member
    Join Date
    Aug 2010
    Posts
    7
    Rep Power
    0

    Default

    at line 30 it says :

    The type KeyBindingGui is already defined

    don't know what to do about that

  16. #16
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Quote Originally Posted by MagnusLarsen View Post
    at line 30 it says :

    The type KeyBindingGui is already defined

    don't know what to do about that
    You have another class in view that already is named this. You could do a search/replace and change KeyBindingsGui to say, KeyBindingsGui2.

Similar Threads

  1. Checking if a button was pressed in a Window.
    By Valkyrie in forum New To Java
    Replies: 2
    Last Post: 12-15-2009, 05:28 AM
  2. data structure with multiple keys
    By jon80 in forum New To Java
    Replies: 2
    Last Post: 06-13-2009, 03:02 PM
  3. get key pressed
    By prashant in forum Networking
    Replies: 1
    Last Post: 03-26-2009, 09:10 PM
  4. Multiple types in Vector - type checking
    By Excession in forum Advanced Java
    Replies: 5
    Last Post: 07-13-2008, 07:06 PM
  5. key pressed event
    By kavithas in forum New To Java
    Replies: 7
    Last Post: 12-10-2007, 02:01 PM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •