Algorithm to detect long and normal keyPressed event in java - java

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.

Related

Java get simultaneos input from key listener

I am creating a simple game in which a keypressed event moves a JLabel a certain number of pixels in a JPanel.
It works without any errors and when i hit the right arrow it moves right, and so on. However, as soon as i press a second key it interrupts the original movement.
For example if i was holding down the left key (and the object was moving left) and then i hit the up arrow the object stops moving left. This is (of course) because i am using only one key event for all my key.
This obviously is not an acceptable situation because as soon as i add a second object (for another player) each player will be constantly stopping the other players movement.
So my question is this: How best can i incorporate multiple simultaneous key actions? (preferably without writing dozens of KeyAdapter's and KeyEvent's)
INFO: currently i have a second class which extends a KeyAdapter. This second class includes a KeyPressed function which then uses .getKeyCode(); to find out which key is pressed and act.
EDIT: any suggestions are welcome!
The solution is actually quite simple. When a key pressed event is registered store a variable that records the movement. When a key released event is registered un-store that variable.
This then means that until you release you keys the movement will continue to be registered. The solution also requires a timer in order to loop repeatedly and check if your event is running or not. You could use a delay but a separate thread is the most effective for this type of task.
First you need a global variable that can store your action:
String action = "";
Then you need a key listener to record your input and when you stop inputting:
// create key listener
addKeyListener(new KeyListener()
{
#Override
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
String event = KeyEvent.getKeyText(keyCode);
if (event.equals("A")) {
// DO YOUR EVENT IF THE KEY HAS BEEN PRESSED
action = "A";
}
}
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
String event = KeyEvent.getKeyText(keyCode);
if (event.equals("A")) {
// STOP DOING YOUR EVENT
action = "";
}
}
});
Lastly you will need a timer thread to loop and do your action:
// CREATE A TIMER THREAD
Timer timer = new Timer();
timer.schedule(new TimerTask() {
// this is what happens every time the timer runs
#Override
public void run() {
// check if your action should be preformed
if (action.equals("A")) {
// ... do something
}
}
}, 0, 1000); // 1000 MILLESECONDS = 1 SECOND
// note: you will need to run 'timer.cancel();' at some point to end your timer
Also it is worth looking at these other topics, including this about keylistener is games. And about timer tasks.

Adjust Key Pressed So You Cant "Hold" it

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.

How to have background input in Java

I would like to be able to have background input in Java. I set up the keyboard listener the usual way (I think). This code works fine, but whenever the program loses focus, the keys stop updating. The update method is ran 60 times a second and continues to be ran while the frame is out of focus, but the keys don't update (If a key is pressed when the frame loses focus, the program will act as if you are holding it down).
My question: is there a way to allow Java to receive background inputs when the frame is out of focus? I would prefer a solution without external libraries but any will help.
The reason I would like to do this is because my program will have multiple frames and I need to be able to receive input in the main frame even if it is not in focus, including when none of the frames are in focus.
Not sure how helpful it will be but my current code for listening for key events is below.
Here I add the key listener to my main class.
public static Keyboard key;
key = new Keyboard();
addKeyListener(key);
This code is from my Keyboard class
private boolean[] keys = new boolean[120];
public boolean up, down, left, right;
public void update() {
up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W];
down = keys[KeyEvent.VK_DOWN] || keys[KeyEvent.VK_S];
left = keys[KeyEvent.VK_LEFT] || keys[KeyEvent.VK_A];
right = keys[KeyEvent.VK_RIGHT] || keys[KeyEvent.VK_D];
}
public void keyPressed(KeyEvent e) {
keys[e.getKeyCode()] = true;
}
public void keyReleased(KeyEvent e) {
keys[e.getKeyCode()] = false;
}

Delay between keystrokes for 2 or more digit number entry

I need to have my program take in numbers from the keyboard, but need to allow for numbers of multiple digits to be entered.
My listeners look like this:
class.getRootPane().getInputMap(JRootPane.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(49,0, false), "one");
class.getRootPane().getActionMap().put("one", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("1 pressed");
}
});
//2
class.getRootPane().getInputMap(JRootPane.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(50,0, false), "two");
class.getRootPane().getActionMap().put("two", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("2 pressed");
}
});
I am proposing to have a global integer stored, which, if clear would cause an action like:
if (numberfield.isEmpty()){
number = 1;
wait for half a second
if wait is over commit number to function and clear numberfield
}//resulting in "1"
else if (numberfield.isnotEmpty()){
"you must have caught it in time"
numberfield = "numberfield"+"1";
wait for half a second
if wait is over commit number to function and clear numberfield
}//resulting in "11" if 1 was pressed twice
My question is this: what is the best way to implement this "delay" I am afraid Thread.sleep(500); or something of the like would cause my listeners to stop working. It there an easier way to do this than setting up a timer and checking every half a second?
I'm not sure what you are doing based on the posted code. You are attempting to use the root pane which would indicate you don't have any focusable components on your GUI.
The easiest solution is to add DocumentListener to each text field. Whenever a DocumentEvent is generated you start/restart a Timer. If the Timer fires then you commit the number and clear the field.
If you are doing this for all text fields on the GUI then it might be easier to check out Global Event Listeners. You should be able to use a KeyEventPostProcessor. Every time a KeyEvent is generated your restart your Timer. If the Timer fires then you commit the number and clear the field.
i think it would be best to just use a listener:
KeyListener l = new KeyListener() {
long lastPress = System.currentTimeMillis();
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == '0' || e.getKeyChar() == '1' || e.getKeyChar() == '2' || e.getKeyChar() == '3' || ..........(keys you want)...) {
if (System.currentTimeMillis() - lastPress >= delay) {
lastPress = System.currentTimeMillis();
yourInputString += e.getKeyChar();
}
}
}
}
addKeyListener(l);
then to get the number put in use int number = Integer.intValue(yourInputString);

Need help with pressing multiple keys in java

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.

Categories

Resources