This question already has answers here:
Java KeyListener stutters
(3 answers)
Closed 9 years ago.
Okay, so I am making a 2D side scroller game for school. It is pretty much just like Mario (well, that is my hope for when I finish.) When I press the right arrow key to move my player along the map, he moves once, pauses, and then begins to smoothly move a lot. I think this is because of the pause that is in all apple laptops when you hold a key down, but I do not know how to get around this for my game. Any advice? Thank you.
One solution is to set boolean keyUP = true inside the keypressed method and keyUP = false inside the keyreleased method. This way once the key has been pressed your game registers this as "keep moving up" until you release the key, instead of "Up was pressed move up, up was pressed move up....". This removes that initial lag (very noticable on linux) on input.
From our game:
private boolean up, down, left, right;
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_S:
down = false;
break;
case KeyEvent.VK_W:
up = false;
break;
case KeyEvent.VK_A:
left = false;
break;
case KeyEvent.VK_D:
right = false;
break;
}
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_S:
down = true;
break;
case KeyEvent.VK_W:
up = true;
break;
case KeyEvent.VK_A:
left = true;
break;
case KeyEvent.VK_D:
right = true;
break;
Although you have not sent any code snippet I can assume the following. I think that you have implemented key listener that does something when key is pressed. If user remains pressing the key your program gets the second event after some delay and then starts getting the events faster.
This is not what you need. You probably should hold some kind of application state keyIsPressed that is changed only once when the key is down (not pressed) first time. Then turn this variable off only when key is up. When key is down first time start background thread that moves your object and checks the flag keyIsPressed periodically to know when to stop.
Good luck to become a competitor of Mario... :)
If this is a Swing GUI, then use Key Bindings, not a key listener,
start a Swing Timer on key press
and stop it on key release.
All KeyEvents are integers, so you can make boolean[] which will store all changes in KeyEvents. For Java2d am using something like this:
import java.awt.KeyEventDispatcher;
import java.awt.event.KeyEvent;
public final class Keyboard implements KeyEventDispatcher {
public static boolean[] keyPressed = new boolean[256];
public static boolean[] keyHold = new boolean[256];
public static boolean[] keyReleased = new boolean[256];
public static void update() {
for (int i=0; i<128; i++) {
keyPressed[i] = false;
keyReleased[i] = false;
}
}
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID()==KeyEvent.KEY_PRESSED) {
keyHold[e.getKeyCode()] = true;
keyPressed[e.getKeyCode()] = true;
}
else if (e.getID()==KeyEvent.KEY_RELEASED) {
keyHold[e.getKeyCode()] = false;
keyReleased[e.getKeyCode()] = true;
}
return false;
}
}
I am calling update() after each frame.
Related
Wasn't sure how to word the title.
I have some code for my "space invaders" type game. I made the entire thing just making adjustments. To shoot, i use spacebar. The problem is im able to hold spacebar and it continually shoots. I would rather have to press it multiple times (if i hold it down.. for it not to continually fire) How would i change it?
*here is the code i believe is the source of the problem. If the source is located elsewhere please say so.
private class KeyInputHandler extends KeyAdapter {
private int pressCount = 1;
/**
* key pressed
*/
public void keyPressed(KeyEvent e) {
if (waitingForKeyPress) {
return;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
leftPressed = true;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
rightPressed = true;
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
firePressed = true;
}
}
/**
* Key Released
*/
public void keyReleased(KeyEvent e) {
if (waitingForKeyPress) {
return;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
leftPressed = false;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
rightPressed = false;
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
firePressed = false;
}
}
added code
public class ShotEntity extends Entity {
//vertical speed
private double moveSpeed = -300;
private Game game;
private boolean used = false;
/**
* Create a new shot from the player
*/
public ShotEntity(Game game,String sprite,int x,int y) {
super(sprite,x,y);
this.game = game;
dy = moveSpeed;
}
/**
* Request that this shot moved based on time
*/
public void move(long delta) {
super.move(delta);
if (y < -100) {
game.removeEntity(this);
}
}
//collision
public void collidedWith(Entity other) {
// prevents double kills.
if (used) {
return;
}
// alien killed
if (other instanceof AlienEntity) {
game.removeEntity(this);
game.removeEntity(other);
game.notifyAlienKilled();
used = true;
}
}
}
Listen for two seperate key events. One when the key is pressed, and one when it is released. Now, you make a boolean.
public boolean myBoolean;
When the key is pressed, set the boolean to true (myBoolean==true)and if it is released, set it to false (myBoolean==false).
Now, create a simple if statement:
if(myBoolean==true){ //Key is being held down
//execute this code
//Have nothing be done
}
Thats it!
P.S. If you want, you can have one separate method to clean up the code. This method could just change the value of the boolean:
public void changeValueOfBoolean(Boolean b){
if(b = true){
return false;
}
if(b==false){
return true;
}
}
It's very simple. Let me know if you need any help, and if this was helpful, please mark it as best answer. Feel free to ask me any questions, I am always happy to help!
Clarifications:
Okay, so we have this boolean, right? Now, this boolean essencialy decides whether the key is pressed or not.
Say we press the button:
Because the key is being held down, we make the boolean myBoolean as true. Now, because the user is holding the key down, we want to do nothing, right? That's why we created that if statement:
if(myBoolean==true){ //Key is being held down
//execute this code
//Have nothing be done
}
It says, if the boolean is true, then we won't do anything. Recall, the boolean is true when the key is being held down, remember? So, when the key is held down, the boolean is true, and nothing will be done.
Now, when the user releases the key:
Now, say the user has pressed the key. This will call two listeners. One listener for when the key is pressed and another for when it is released. If the user just presses the key, myBoolean will end as false, since they have let go of the key. Therefore, we can execute some code when myBoolean is false (shooting).
**In summary:
myBoolean is true when when the key is being held down. So, when it is true, we do nothing. myBoolean is false when the user lets go of the key, and there, we shoot the space invaders.**
Simple, just have a Boolean variable which causes the ship to shoot only when it is true. Then set it to true in the space bar is pressed and set it to false when the ship shoots. I can't show you how to implement it in your program as I don't know how your shoot method works. However, if you were to post the method which causes the ship to shoot then, I could show you how to implement it or, you could try your self.
I'm developing a little 2D game like Mario Bros, in this game when the user press the jump button depends of the milliseconds the jump button is pressed, Mario performs a small jump or a larger jump.
I tried to declare a counter that increments into my keyPressed event but not working...
contadorSalto = 0;
contadorTiempoSalto = 0;
public void keyPressed(KeyEvent arg0) {
int codigo = arg0.getKeyCode();
if(codigo == KeyEvent.VK_SPACE)
{
System.out.println(contadorTiempoSalto);
contadorTiempoSalto++;
map.put("espacio", true);
}
}
public void moverPersonaje(){
if(map.get("espacio")&&(contadorSalto < 1)){
if(contadorTiempoSalto == 0){//less tant 1 second
pj[0].setVelocidadY(-15);
}
if(contadorTiempoSalto > 0){
pj[0].setVelocidadY(-25);
}
contadorSalto++;
}
}
I can paste the rest of code if you want! Thanks
Instead of just recording that a key has been pressed in your map, record when the key has been pressed. Also add a keyReleased() handler that clears the key from the map.
You can then easily find out for how long the key has been pressed:
public Map<Integer, Long> keyPressMap = new HashMap<>();
public void keyPressed(KeyEvent arg0) {
keyPressMap.put(arg0.getKeyCode(), System.currentTimeMillis());
}
public void keyReleased(KeyEvent arg0) {
keyPressMap.remove(arg0.getKeyCode());
}
// find out if key is pressed and how long it was
Long t = keyPressMap.get(KeyEvent.VK_SPACE);
if (t == null) {
// not pressed
} else {
// pressed for X milliseconds
long millis = t - System.currentTimeMillis();
}
You can then decide what to do on how long the key has been down.
Generally, you shouldn't rely on the keyPressed() and keyReleased() functions. Instead, use booleans that keep track of whether each key you care about is pressed, and set those booleans in the keyPressed() and keyReleased() functions.
Then in your game loop, check those booleans to determine which keys are currently pressed. Then either keep track of the number of frames a boolean is true, or record the system time when the boolean changes to get the elapsed time.
So basicaly what im trying to do is using LWJGL now making my player move in the game. The player is currently moving but he doesnt keep mooving while you are holding the button..
public void update(){
while(Keyboard.next()){
if(Keyboard.getEventKey() == Keyboard.KEY_RIGHT) {
if(Keyboard.getEventKeyState()){
System.out.println("KEY DOWN!");
player.playerMovingRight();
}
else{
System.out.println("KEY RELEASED!");
}
}
}
I tried using a while(Keyboard.getEventKeyState()) but it just made the game crash and it wouldnt recognise if i release the key.
So how can i make my player keep moving if you hold the button instead of having to rapidly press the key to move. And how would i make it work if the player is holding 2 buttons at the same time?
Updated code:
public void update(){
while(Keyboard.next()){
//If key escape is down we shut the application down
if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)){
System.exit(0);
}
//If key up was pressed move up
else if(Keyboard.getEventKey() == Keyboard.KEY_UP) {
if(Keyboard.getEventKeyState()){
System.out.println("KEY DOWN!");
moveUp = true;
}
else{
System.out.println("KEY RELEASED!");
moveUp = false;
}
}
//If key down was pressed move down
else if(Keyboard.getEventKey() == Keyboard.KEY_DOWN) {
if(Keyboard.getEventKeyState()){
System.out.println("KEY DOWN!");
moveDown = true;
}
else{
System.out.println("KEY RELEASED!");
moveDown = false;
}
}
if(moveUp == true){
player.playerMovingUp();
}
if(moveDown == true){
player.playerMovingDown();
}
}
Im still having the same problem with the code, Im starting to think its they Keyboard.next() that is preventing me from holding the button and the player still moves.
What you need is a boolean flag which triggers when the button is pressed down, and is untriggered when the button is released. The flag would then be added to an if statement before the movement code. Like so:
if(Keyboard.getEventKey() == Keyboard.KEY_RIGHT) {
if(Keyboard.getEventKeyState()){
System.out.println("KEY DOWN!");
flag = true;
}
else{
System.out.println("KEY RELEASED!");
flag = false;
}
}
}
//player movement code
if(flag) {
player.playerMovingRight();
}
The way to do it with multiple keys is to use an array of boolean triggers and repeating the checks for each key.
While the above answer will work, LWJGL has the capability to detect if a key is being held down. It is not enabled by default though, so you need to enable it. To do this just set this flag to true somewhere in your input initialization.
Keyboard.enableRepeatEvents(true);
Now in your event loop, just do this check on your keys to see if it is a repeat (held down key).
if(Keyboard.isRepeatEvent())
Here is a small sample to see how to check a key for different key states.
while(Keyboard.next())
{
if(Keyboard.getEventKey() == Keyboard.KEY_A)
if(Keyboard.getEventKeyState())
{
if(Keyboard.isRepeatEvent())
// Key held down
else
// Key pressed
}
else
// Key released
}
while(Keyboard.next()) is supposed to be used with events.
In your case, you don't want to only do something, when an event gets triggered. But you want to determine many times per second, whether a key is pressed or not. If it is, you want to do something (e.g. move).
So it's the best solution to use the Keyboard.isKeyDown() function.
A little example:
if (Keyboard.isKeyDown(Keyboard.KEY_UP)) {
System.out.println("pressing KEY_UP");
}
if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
System.out.println("pressing KEY_DOWN");
}
if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) {
System.out.println("pressing KEY_LEFT");
}
if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) {
System.out.println("pressing KEY_RIGHT");
}
Also, a good tutorial can be found here.
I found a very good tutorial about how to create games with Java2D. In this tutorial there is a section called 'Moving sprites' that shows how to move a little spacecraft image on the screen. I was playing with the craft and realized that it was "blocking" on screen sometimes. After some tests and thinking about the problem I found out that the blocking problem was happening because when you use the arrows of the keyboard sometimes you press Left and Right at same time for example, and this blocks the movement.
So my question is: how do I handle this kind of keyboard event - when you are pressing LEFT button keep pressing it and then press RIGHT button - so the character movement is not blocked?
I think this is very common to happen because when you are playing you switch from left to right but for an instant you are pressing left and right at the same time.
You can do this in multiple ways. One way is to use booleans in your program.
You can set booleans to true when you press a certain key and to false when you release them. ie:
int x,xSpeed;
boolean movingLeft = false;
boolean movingRight = false;
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT){
movingLeft = true;
}
if(key == KeyEvent.VK_RIGHT){
movingRight = true;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT){
movingLeft = false;
}
if(key == KeyEvent.VK_RIGHT){
movingRight = false;
}
}
public void moving(){
if(movingLeft){
x -= xSpeed;
}
if(movingRight){
x += xSpeed;
}
}
Ok let's look at this code. Because we're using the 'else if' you either move right, or you move left. I haven't test this code so not quite sure if this will work :)
Let me know what you think and good luck!
I'm trying to code a game similar to Mario in Java and am having problems with making the dude jump while he is running. What the below code ends up doing is, as the user is holding down right and presses the jump button, Mario basically stops running and jumps, so its like the user has let go of right and pressed jump.
public void keyPressed(KeyEvent e) {
// here I keep track of what buttons the user pressed
int keyCode = e.getKeyCode();
if(keyCode == 37)
pressedKeys[0] = true;
else if(keyCode == 39)
pressedKeys[1] = true;
else if(keyCode == 68)
pressedKeys[2] = true;
// after I see what the user has pressed an action is carried out
Thread t = new Thread(this);
t.start();
}
public void performAction()
{
// depending on what the user has pressed a certain action is performed
if(pressedKeys[2]==true)
{
// changes the coordinates of the character itself
// done in another thread so the background can continue
// moving as the user holds down a direction
Thread t = new Thread(mcControl);
t.start();
}
if(pressedKeys[0]==true)
{
changeSprite();
bg.moveImageForward();
}
if(pressedKeys[1]==true)
{
changeSprite();
bg.moveImageBackward();
}
}
public void run() {
performAction();
}
if(keyCode == 37)
Not related to your problem, but NEVER use code like that. Most people don't know what that magic number means.
The better way to do this is to use:
if(keyCode == KeyEvent.VK_???)
Now your code is self documenting.
You want to take a look at How to Write a Key Listener. The KeyEvent object has several methods for learning what modifier keys and mouse buttons were pressed at the time the event was generated.