How do I handle simultaneous key presses in Java?
One way would be to keep track yourself of what keys are currently down.
When you get a keyPressed event, add the new key to the list; when you get a keyReleased event, remove the key from the list.
Then in your game loop, you can do actions based on what's in the list of keys.
handle multiple key presses ignoring repeated key
Your obseravtion that things are handled slowly most likely is caused solely be the many System.out.println() statements.
Your problem that you do not get diagonal movement stems from your somewhat faulty checking logic - instead of explicitly checking if (for example) keys A and B are pressed, just check them independently - key A moves the character in one direction, B in another. In total (e.g.), by moving WEST and NORTH you will have effectively moved NORTHWEST.
Instead of a list of pressed keys, you could use a java.util.BitSet and just set the bit for each key that is currently pressed. That should also drastically reduce the amount of code you need to write (keyPressed just sets the bit indicated by key code, keyReleased clears it). To check if a key is pressed you ask the BitSet then if the bit for the code is currently set.
EDIT: Example of using BitSet instead of a list
public class BitKeys implements KeyListener {
private BitSet keyBits = new BitSet(256);
@Override
public void keyPressed(final KeyEvent event) {
int keyCode = event.getKeyCode();
keyBits.set(keyCode);
}
@Override
public void keyReleased(final KeyEvent event) {
int keyCode = event.getKeyCode();
keyBits.clear(keyCode);
}
@Override
public void keyTyped(final KeyEvent event) {
// don't care
}
public boolean isKeyPressed(final int keyCode) {
return keyBits.get(keyCode);
}
}
I made the example implement KeyListener, so you could even use it as is. When you need to know if a key is pressed just use isKeyPressed(). You need to decide if you prefer with raw key code (like I did) or go with key character (like you currently do). In any case, you see how using the BitSet class the amount of code for recording the keys reduces to a few lines :)
Multiple keys pressed in Java
How about:
class MultiKeyPressListener implements KeyListener {
// Set of currently pressed keys
private final Set<Integer> pressed = new HashSet<Integer>();
@Override
public synchronized void keyPressed(KeyEvent e) {
pressed.add(e.getKeyCode());
if (pressed.contains(KeyEvent.VK_UP)) {
if (pressed.contains(KeyEvent.VK_LEFT)) {
starfighter.moveUpLeft();
}
if (pressed.contains(KeyEvent.VK_RIGHT)) {
starfighter.moveUpRight();
}
}
}
@Override
public synchronized void keyReleased(KeyEvent e) {
pressed.remove(e.getKeyCode());
}
@Override
public void keyTyped(KeyEvent e) {/* Not used */ }
}
}
Note how you have a set of Integers instead of Characters and store key codes instead of key characters.
Java swing - Processing simultaneous key presses with key bindings
I personally would use the KeyListener interface to keep track of what the user has typed and then just register within a List the keys that have been pressed (without releasing) and then collect them once any key has been released.
Make sure though to add to the list only the keys that are not present yet because the keyPressed event is fired multiple times while the user is holding down a key.
I've also created a little sample to give you the idea.
public class MyClass extends JFrame implements KeyListener {
private JTextArea textArea;
private List<Character> listKeys;
public MyClass() {
setTitle("test");
listKeys = new ArrayList<>();
textArea = new JTextArea();
textArea.addKeyListener(this);
setLayout(new BorderLayout());
add(textArea, BorderLayout.CENTER);
setLocation(50, 50);
setSize(500, 500);
setVisible(true);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (!listKeys.contains(e.getKeyChar())) {
listKeys.add(e.getKeyChar());
}
}
@Override
public void keyReleased(KeyEvent e) {
if (listKeys.isEmpty()) {
return;
}
if (listKeys.size() > 1) {
System.out.print("The key combination ");
} else {
System.out.print("The key ");
}
for (Character c : listKeys) {
System.out.print(c + " ");
}
System.out.println("has been entered");
listKeys.clear();
}
public static void main(String[] args) {
new MyClass();
}
}
Swing's KeyListener and multiple keys pressed at the same time
Use a collection to remember which keys are currently pressed and check to see if more than one key is pressed every time a key is pressed.
class MultiKeyPressListener implements KeyListener {
// Set of currently pressed keys
private final Set<Integer> pressedKeys = new HashSet<>();
@Override
public synchronized void keyPressed(KeyEvent e) {
pressedKeys.add(e.getKeyCode());
Point offset = new Point();
if (!pressedKeys.isEmpty()) {
for (Iterator<Integer> it = pressedKeys.iterator(); it.hasNext();) {
switch (it.next()) {
case KeyEvent.VK_W:
case KeyEvent.VK_UP:
offset.y = -1;
break;
case KeyEvent.VK_A:
case KeyEvent.VK_LEFT:
offset.x = -1;
break;
case KeyEvent.VK_S:
case KeyEvent.VK_DOWN:
offset.y = 1;
break;
case KeyEvent.VK_D:
case KeyEvent.VK_RIGHT:
offset.x = 1;
break;
}
}
}
System.out.println(offset); // Do something with the offset.
}
@Override
public synchronized void keyReleased(KeyEvent e) {
pressedKeys.remove(e.getKeyCode());
}
@Override
public void keyTyped(KeyEvent e) { /* Event not used */ }
}
Java - KeyListener Multiple Keys
A lot of people have that problem. It is called Keyboard Ghosting
and means that some combinations simply don't work on cheap keyboards. Thats why high class gaming keyboards exists. So nothing wrong with your code. No optimization possible. You need to use key combination that work.
To proof my answer here are some links for you.
http://board.flashkit.com/board/showthread.php?789015-wont-respond-to-keyboard-up-left-and-space-at-the-same-time
http://forums.steampowered.com/forums/showthread.php?t=1928521
http://www.tomshardware.co.uk/answers/id-2159074/alt-space-bar-work-holding-left-arrow.html
https://unix.stackexchange.com/questions/268850/leftupspace-keys-not-working-on-thinkpad-x201
How do I handle multiple key presses in a Java Applet?
What you usually do is to remember the state of every keypress.
You keep an array of your actions(or an array of all the keys if you want too). A keyDown event results in e.g.
boolean actions[12];...
...
public boolean keyDown( Event e, int key ) {
if (key == 'a') {
actions[ACTION_LEFT] = true;
}
..
}
And you'll need to catch the keyup event and set the actions to false when the keys are released.
In the movement logic you can just check the states of the keypresses
if(actions[ACTION_LEFT] == true)
moveLeft();
if(actions[ACTION_RIGTH] == true)
moveRight();
Related Topics
How to See the Source Code of the Sun Jdk
Calculating the Distance Between Two Points
How to Find Out What Type Each Object Is in a Arraylist<Object>
Why Isn't a Qualified Static Final Variable Allowed in a Static Initialization Block
Is This a Bug in Files.Lines(), or am I Misunderstanding Something About Parallel Streams
How to Format Localdate to String
What Is Inside Com.Sun Package
How to Serialize a List in Java
How to Pass a Variable from One Thread Group to Another in Jmeter
How to Enable Commit on Focuslost for Tableview/Treetableview
How to Write a Compareto Method Which Compares Objects
How to Change My Windows Desktop Wallpaper Programmatically in Java/Groovy
How to Test If My Font Is Rendered Correctly in PDF
Why Does Autoreconnect=True Not Seem to Work
Dealing with Randomly Generated and Inconsistent JSON Field/Key Names Using Gson
Keylistener, Keypressed Versus Keytyped