I am teaching myself, from online tutorials, how to write games in Java. I am using Java Applets to create a Pong game. each paddle is controlled from different keys for 1v1 competition. this works fine if both users are hitting the keys at different times. but when one key is being held down and then another key is held down(ex: holding down on the arrow key, then user 2 holds the 'S' key), the second key overrides the first and the first paddle will stop moving. i'm guessing that i need to use threads but i don't know much about them and i am having trouble understanding how to use/implement them. how would i go about handling the case when two (or more) keys are being held down?
Bonus: like i said i don't know much about threads - i'm assuming i also need one for the ball/puck to be moving around while all else is going on. is the right and if so how do i put a thread on something that takes no input?
Thanks for you help,
DJ
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();
Usually instead of threads, games use something called the game loop (google it).
http://en.wikipedia.org/wiki/Game_programming
The basic idea is
Loop
Get all inputs
Get game clock
Update state based on clock and inputs
Update Display
Limit frame rate if you need to
Anyway -- instead of getting keyboard events -- you check the keyboard's state at certain points. This code seems to do it for Java
http://www.gamedev.net/reference/articles/article2439.asp
It uses events to set variables you look at in your loop.
Just in case anyone wanted to see how I ended up answering this question. My keyDown() and keyUp() method are as follows:
public boolean keyDown(Event e, int key)
{
message = key + "pressed";
//right paddle
if(key == 1005)
{
rpaddle_up = true;
}
if(key == 1004)
{
rpaddle_down = true;
}
//left paddle
if(key == 115)
{
lpaddle_up= true;
}
if(key == 119)
{
lpaddle_down=true;
}
//x key = exit
if(key == 'x')
System.exit(0);
return true;
}
public boolean keyUp(Event e, int key)
{
//right paddle
if(key == 1005)
{
rpaddle_up = false;
}
if(key == 1004)
{
rpaddle_down = false;
}
//left paddle
if(key == 115)
{
lpaddle_up= false;
}
if(key == 119)
{
lpaddle_down=false;
}
return true;
}
Hopefully if someone has the same issue this will help them. And thanks everyone for your input and help.
If I'm not mistaken, you have the keyUp() and keyDown() methods at your disposal with Applet. Have you tried setting a flag on keyDown, then unsetting it on keyUp? For example:
public boolean keyDown( Event e, int key )
{
if (key == 'a') {
player1.go("left")
}
}
public boolean keyUp( Event e, int key )
{
if (key == 'a') {
player1.stop("left")
}
}
Just an idea. I'm sure there's a standard way to deal with this.
You could use Swing Timer to periodically fire movement events between a keydown/keyup event.
Related
I am trying to create a sketch that will use the WASD keys to move a character around the screen in the Processing 3.3.7 IDE.
I am having an issue when one key is released and another is pressed at the same time, the key variable will not change to the new input for about a second. I cut down the offending code to this:
void draw(){
println(key);
}
With this code you can see, when you release one key and begin holding another in as close succession as possible (possibly only on the same frame) the printed value will not change for about a second (might differ depending on what your key repeat time). This is really annoying and I don't know how to get around it.
Thanks for reading!
The println() function is notoriously bad at timing, so I wouldn't trust it for micro-benchmarks like this.
Also, the key variable holds the last key that was interacted with, which could be the key you released instead of the key you pressed. For example, think about this sequence of events:
I press the a key. The key variable becomes a.
I press the s key. the key variable becomes s.
Now I release the a key. the key variable switches back to a.
I'm still holding the s key, so after a second, my keyboard triggers another s key event, switching the key variable to s.
If you want more fine-grained control over the keyboard events, I suggest using the event functions like keyPressed() and keyReleased(). You probably want to keep track of which keys are pressed using a set of variables that you set in the event functions. Here's an example:
boolean aPressed = false;
boolean sPressed = false;
void draw(){
if(aPressed){
// a is pressed
}
if(sPressed){
// s is pressed
}
}
void keyPressed(){
if(key == 'a'){
aPressed = true;
}
else if(key == 's'){
sPressed = true;
}
}
void keyReleased(){
if(key == 'a'){
aPressed = false;
}
else if(key == 's'){
sPressed = false;
}
}
Shameless self-promotion: here is a tutorial on handling input events. See the handling multiple key presses section to read more about this approach.
I'm developing a Java/Swing application, and I'm making my own handling for key events using a KeyListener on my JFrame.
My problem is, the key repeat feature of the OS is causing multiple keyPressed events to occur when I hold down a key, when I would like to only receive one.
One solution would be to keep the states of the keys in an array, and only accept the event if the state changes.
private boolean keysDown[] = new boolean[0x10000];
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (0 <= key && key <= 0xFFFF) {
if (keysDown[key]) return;
keysDown[key] = true;
}
// ...
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (0 <= key && key <= 0xFFFF) {
if (!keysDown[key]) return;
keysDown[key] = false;
}
// ...
}
This works, but is very clumsy, and while I only seem to find keycodes in the range 0 to 216-1, I'm not sure if ones outside that range can exist. (getKeyCode() returns int.) Another problem is that pressing down a key, releasing it while in another window, and pressing it again in my application would not register the event.
So, is there a better way to either
disable key repeat in my application or
detect repeated events reliably?
Replace your boolean array with HashSet<Integer> or TreeSet<Integer>. The key repeat is a function of the OS, so there is no way to disable it, only account for it.
Hi, I wish to know why the AND operator is not working here? Even though without operator it working fine what is wrong while including it?
else if (keyCode == KeyEvent.KEYCODE_CTRL_LEFT && keyCode == KeyEvent.KEYCODE_S) {
int visibility=new_Sell_order_cart.getVisibility();
if(visibility==View.VISIBLE)
{
openCart();
}
}
If its not possible how jQuery developer Achive this
if (e.keyCode == 65 && e.ctrlKey) {
alert('ctrl A');
}
});
keyCode cannot be two keys at once. It can be either CTRL_LEFT or KEYCODE_S.
This statement returns false because either one will be true but not both.
(Its like a==3 && a==4, a cannot be 3 and 4 at the same time)
keyCode == KeyEvent.KEYCODE_CTRL_LEFT && keyCode == KeyEvent.KEYCODE_S
Probably you are looking for OR (||) operator:
else if (keyCode == KeyEvent.KEYCODE_CTRL_LEFT || keyCode == KeyEvent.KEYCODE_S) {
EDIT:
If you want to check for two keypress. Here is the solution suggested in this post.
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.
I got one Solution , I know it is not up-to mark but it full-fill my requirement .
else if (isCTRLisPressed(17) && keyCode == KeyEvent.KEYCODE_S) {
int visibility=new_Sell_order_cart.getVisibility();
if(visibility==View.VISIBLE)
{
openCart();
}
}
and
public boolean isCTRLisPressed(int i){
if(i==17){
System.out.println(" key code of ctrl"+i);
return true;
}
else {
System.out.println("key code in else "+i);
return false;
}
}
My problem is explained in the following scenario
There are 2 JTextField objects. Let's give them variable names as jTextField1 and jTextField2. And the current focus owner is jTextField2. And the User and/or a Device is firing key inputs into the program. But according to the speed of each key being pressed and released the program should decide which text field the key char of that key input should be entered into. For an example, if the difference between KEY_PRESSED and KEY_RELEASED is less than or equal to 50 milliseconds, the Key Char should be typed into jTextField1 and never into jTextField2 but while the Focus is still owned by jTextField2 and unchanged. If the difference between the events are greater than 50 milliseconds, the text will be typed into its current Focus Owner which is jTextField2 (Or it may be any other object too according to what the User has the Focus at the moment.). So if there were 2 simultaneous activities happening, for an example a user is typing keys in a speed of greater than 50 milliseconds per key typing, and another device like a Barcode Scanner is firing Key Events in a speed less than 50 milliseconds, both of these inputs should be entered or typed into those different text fields separately according to their typing speeds while the focus owner is always at the object which the user is interacting with.
Here is the current code I have written which works well but with the problem that when keys are pressed in a speed less than 50 milliseconds per key, it sets at jTextField1 but it also gets typed at jTextField2.
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
millis = System.currentTimeMillis();
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
enter1 = true;
}
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
if ((System.currentTimeMillis() - millis) <= 10) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
enter2 = true;
} else {
barcodeStringBuilder.append(e.getKeyChar());
}
if (enter1 && enter2) {
compo = getFocusOwner();
jTextField1.setText(barcodePool.toString());
barcodeStringBuilder.setLength(0);
compo.requestFocus();
}
enter1 = false;
enter2 = false;
} else {
}
} else if (e.getID() == KeyEvent.KEY_TYPED) {
}
return false;
}
The previous attempt I made to accomplish this task was trying to handle the input of the two devices which are a Keyboard and a Barcode Scanner separately using the Java HID API which also was unsuccessful. You can find my question thread on it here. And then I made it into this option which so far seems to be a good option.
So, does anyone know an effective way to accomplish my task as I have described above?
Thank you! And your help is highly appreciated.
I would not give either JTextFields focus, would not use a KeyEventDispatcher, but would instead try to use Key Bindings, and then based on the timing, append the text into the appropriate text field. This would prevent focus issues sending the text to two text fields.
i'm using the keyboard class from the LWJGL and am currently using
if(Keyboard.isKeyDown(Keyboard.KEY_A))
{
//move left
}
else if(Keyboard.isKeyDown(Keyboard.KEY_D))
{
//move right
}
if i have the 'a' key down then the 'd' key it will move right but if i have the 'd' key down then the 'a' key it will still continue to move right due to the "else" part.
i've tried it without the else and just letting them both run but if both keys are press there is no movement
im looking for a piece of code that allows me to only take the input from the last key that was pressed.
i also need to be able to move up and down (using 'w' and 's') so the solution can't stop other keys from working, only 'a' or 'd'.
thanks. Alex.
Use Keyboard.getEventKeyState to determine the current event, followed by Keyboard.getEventKey to determine which key this is. Then, you need to make sure you disable repeat events via Keyboard.enableRepeatEvents. Maintain state for the current movement, changing based on these events, and every tick move accordingly. Something like the following, as quick sketch:
Keyboard.enableRepeatEvents(false);
...
/* in your game update routine */
final int key = Keyboard.getEventKey();
final boolean pressed = Keyboard.getEventKeyState();
final Direction dir = Direction.of(key);
if (pressed) {
movement = dir;
} else if (movement != Direction.NONE && movement == dir) {
movement = Direction.NONE;
}
...
/* later on, use movement to determine which direction to move */
In the above example, Direction.of returns the appropriate direction for the pressed key,
enum Direction {
NONE, LEFT, RIGHT, DOWN, UP;
static Direction of(final int key) {
switch (key) {
case Keyboard.KEY_A:
return Direction.LEFT;
case Keyboard.KEY_D:
return Direction.RIGHT;
case Keyboard.KEY_W:
return Direction.UP;
case Keyboard.KEY_S:
return Direction.DOWN;
default:
return Direction.NONE;
}
}
}
Idk if this is still going to help you, but you could lock the key that was first pressed until it is let up. I'd suggest putting this variable outside of the methods (if I remember correctly, it's called a field) so it can be accessed through any class and isn't reinstantiated every time update is called. That would look something like this:
boolean isHorizontalLocked = false;
String lockedKey = null;
After that, write something like this in the update method:
if (!isHorizontalLocked) {
if (input.isKeyDown("KEY_A")) {
isHorizontalLocked = true;
lockedKey = "A";
}
else if (input.isKeyDown("KEY_D")) {
isHorizontalLocked = true;
lockedKey = "D";
}
else {
isHorizontalLocked = false;
}
}
else if (isHorizontalLocked) {
if (lockedKey == "A") {
if (input.isKeyDown("KEY_A")) {
//move left
}
if (!input.isKeyDown("KEY_A")) {
lockedKey = null;
isHorizontalLocked = false;
}
}
else if (lockedKey == "D") {
if (input.isKeyDown("KEY_D")) {
//move right
}
if (!input.isKeyDown("KEY_D")) {
lockedKey = null;
isHorizontalLocked = false;
}
}
}
I think this should work, but if anyone finds an error, let me know and I'll fix it.