Java2D games: How to handle keyboard correctly? - java

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!

Related

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.

In Java, how to take a character without pressing the enter key?

How can I get characters without pressing the Enter key?
Actually I want to build a game so I need to get characters as moves and then do the moves without the Enter key being pressed.
You could add a keyListener if your using swing example of keyListener:
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_UP)
{
//code here
}
else if(keyCode == KeyEvent.VK_DOWN)
{
//code here
}
//etc...
}
For example I am still learning keyListeners as well. but, to make a e.g Rectangle move you could make a private rectangle call it in your paintComponent() rect.fillRect(0,0,10,10) then use the keyListener to check for input.
public void keyPressed(KeyEvent e){
if (rect.getKeyCode() == KeyEvent.VK_S)
if (rect.getKeyCode() == KeyEvent.VK_F)
xa = 2;
if (rect.getKeyCode() == KeyEvent.VK_E)
ya = 2;
if (rect.getKeyCode() == KeyEvent.VK_D)
ya = -2;
}
EDIT: After, reading that you are not using Swing, it would help to provide some code or further expand on the details of what you want the key to do when pressed in your game.
you should take a look at:
System.in.read();
It reads the next byte of data from the input stream.

LWJGL holding a key pressed

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.

Java: How to detect if a key has been held down over a certain time without checking every loop

EDIT: Notice to others, premature optimisation is the root of all evil! Had I not been busily attempting to optimise every aspect of my code (it was a phase OK!) I'd have made a nice, readable program that could be maintained and understood by others.
Each loop (1/60th of a second) the Player class checks the Game class to see which key is down, If the player is not facing the right way it turns to face the right way, else it moves in that direction.
Sadly this means that if you want to turn and not move you have to tap the key for less than 2/60ths of a second (two loops). The code for checking which key is held down is below
and a link to the full source code and a built example is below that.
public class Game extends RenderableObject
{
public static final byte NONE = 0;
public static final byte UP = 1;
public static final byte RIGHT = 2;
public static final byte DOWN = 3;
public static final byte LEFT = 4;
public byte key = NONE;
public Game()
{
}
#Override
public void keyPressed(KeyEvent ke)
{
if (!paused)
{
if (ke.getKeyCode() == 38) // '^ key'
{
key = UP;
return;
}
else if (ke.getKeyCode() == 40) // 'v key'
{
key = DOWN;
return;
}
if (ke.getKeyCode() == 37) // '< key'
{
key = LEFT;
return;
}
else if (ke.getKeyCode() == 39) // '> key'
{
key = RIGHT;
return;
}
}
}
#Override
public void keyReleased(KeyEvent ke)
{
if (ke.getKeyCode() == 38) // '^ key'
{
if (key == UP)
key = NONE;
return;
}
else if (ke.getKeyCode() == 40) // 'v key'
{
if (key == DOWN)
key = NONE;
return;
}
if (ke.getKeyCode() == 37) // '< key'
{
if (key == LEFT)
key = NONE;
return;
}
else if (ke.getKeyCode() == 39) // '> key'
{
if (key == RIGHT)
key = NONE;
return;
}
}
Link to full source code and built example: (well a link to the page with a link to the download anyway!
WARNING: I am a NOOB, if my naming conventions are off... please don't hurt me!
http://troygametwodee.blogspot.com/2011/09/latest-build-21092011.html
So I have toyed with a few ideas already, but none seem particularly gracefull, and all become very messy very quickly,
I'd ideally like to be able to check some sort of boolean in the game class so the player only moves in that direction when the bool is true, but I failed at that too :(
So if anyone has any suggestions I would be very happy :)
Thanks a bunch in advance
Ok, so how I solved the issue while keeping fluid motion possible:
First I added a boolean variable called "held". This on it's own was useless so I also added
a numerical variable, called "timeHeld". Each time a key was pressed I reset "timeHeld" to zero and made "held" == false, and put the following code into my loop.
if (timeHeld < 20)
timeHeld++;
else
held = true;
So in my player class, when deciding which way to move it calls "Game.key" to asses which key is down, then if the "held" boolean is true (which it is after one third of a second) the player walks in that direction, Otherwise the player stayed where it is on screen and just changed the direction it was looking.
This worked to an extent, but each time I change direction the "held" variable was set to zero again. This means each time I turned I was delayed by a third of a second, very annoying!
So I did this:
if (ke.getKeyCode() == 38) // '^ key'
{
if (key == NONE)
{
held = false;
timeHeld = 0;
}
key = UP;
return;
}
this means that as long as an arrow key is down "held" remains true, so once the player gets moving there is no delay when turning a corner.
This worked absolutely perfectly as it was, so that is the answer, however I also added another variable. Because I only use my middle finger for both the UP and DOWN key while I play using the arrow or 'wasd' keys, I end up letting go of all of the keys when I switch from moving north to south. In this case with the code as described above I end up stopping for a third of a second SO to fix this I added a variable called "delay"
When a key is let go of, delay is set to 10 (loops), each loop I call:
if (delay > 0)
delay--;
then when a key is pressed I call:
if (ke.getKeyCode() == 38) // '^ key'
{
if (key == NONE && delay == 0)
{
held = false;
timeHeld = 0;
}
key = UP;
return;
}
This means that "held" is only ever set to false when a direction key is pressed and there were no other direction keys down at the time it was pressed AND delay is 0. this gives me a 10 loop delay between letting go of all the arrow keys and pressing another one before "held" is set to false.
Confused? I am! but it works, anyone else who has this problem can either follow the link to my blog, which should have the latest working source, or just ask me to explain the bits you don't get :D
A clearer description of what you are trying to achieve would help.
However, if I understand correctly, you could keep a short history of which key is down, e.g. keep the key value for the last five loops. Then you could execute certain actions if at least a certain number of the previous values match a particular key.
try holding a value object with boolean value for all of your actions/keypresses in it. The boolean will be true for keydown and false for keyup. When the key actions are handled you can then update the value object to true/false for the relevant key only.
Then when your game update loop runs you can check which key(s) are currently down.

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