1

I'm making a 2D game in java.

In the game, pressing the left and right arrow keys rotates a sprite and manipulates a variable named 'angle'. Pressing the up arrow key, computes the direction where the sprite should move depending on the 'angle' variable.

This works, but I'm unable to manipulate the angle while moving, aka have left or right keys be pressed at the same time the up arrow is pressed.

Pressing the up arrow makes the program ignore the fact the one of the arrow keys is pressed.

I have searched the forum and found one suggestion how to handle that, but I'm not sure it's the best for my program. (What I found: How do I handle simultaneous key presses in Java?)

Here's some code:

Relevant methods of Thing class:

    public void keyPressed(KeyEvent e){

    int key = e.getKeyCode();

    if(key==KeyEvent.VK_LEFT){ setAngle(getAngle()-5); 
            leftPressed=true; // *new* }
    if(key==KeyEvent.VK_RIGHT)setAngle(getAngle()+5);{
            rightPressed=true; // *new* }
    if(key==KeyEvent.VK_UP){

        dy = (float) ( Math.sin( getAngle() ) ) * 5;
        dx = (float) ( Math.sin( 90-getAngle() ) ) * 5;
                    if(leftPressed==true)angle-=5; // *new*
        if(rightPressed==true)angle+=5; // *new*

    }

public void move(){
    x += dx;
    y += dy;
}

}

The Board class (the class that manages the game:)

package learningMovement;

import java.util.*;
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.Timer;

public class Board extends JPanel implements ActionListener, KeyListener {

    Thing t;

    Timer timer;

    public Board(){
        setBackground(Color.BLACK);
        timer = new Timer(10,this);
        t = new Thing();
        setFocusable(true);
        timer.start();
        addKeyListener(this);
    }

    public void paintComponent(Graphics g)
    {

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        g2d.rotate( Math.toRadians(t.getAngle()), t.getX() + (t.getWidth()/2), t.getY() + (t.getHeight()/2) );
        g2d.drawImage(t.getImage(),(int)t.getX(),(int)t.getY(),this);

    }

    public void actionPerformed(ActionEvent e){

        t.move();
        repaint();

    }

    public void keyPressed(KeyEvent e) {

        int key = e.getKeyCode();

        if(key==KeyEvent.VK_LEFT)t.keyPressed(e);
        if(key==KeyEvent.VK_RIGHT)t.keyPressed(e);
        if(key==KeyEvent.VK_UP)t.keyPressed(e);

    }

    public void keyReleased(KeyEvent e) {

        int key = e.getKeyCode();

        if(key==KeyEvent.VK_LEFT)t.keyReleased(e);
        if(key==KeyEvent.VK_RIGHT)t.keyReleased(e);
        if(key==KeyEvent.VK_UP)t.keyReleased(e);

    }

    public void keyTyped(KeyEvent arg0) {}



}

How do I fix this? Thanks

Community
  • 1
  • 1
user3150201
  • 1,901
  • 5
  • 26
  • 29
  • The referenced answer is a valid way to handle multiple key presses. I would give it a go. – Sully Jan 01 '14 at 09:38

2 Answers2

2

KeyListener will only raise a single event. That means, when ever keyPressed is called, it represents on a single key event.

Instead, what you need to do, is on each time keyPressed is triggered, you need to set a flag, indicating what key was pressed. When keyReleased is triggered, you need to reset the flag.

You then need a method that can process these flags and decisions about what do based on the state of these flags...

Lastly avoid KeyListener, is focus issues which are just a pain to deal with. Instead, I'd recommend that you use Key Bindings instead

For example...

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I answered a question similar to this, albeit the language was AS3. AS3 is similar to Java though and I think it would help the OP, so here's the [link](http://stackoverflow.com/questions/14166083/fluidly-dealing-with-multiple-keypresses-in-actionscript3/14166139#14166139), the update to the answer deals with the OP's question. – Jonny Henly Jan 01 '14 at 09:56
  • @MadProgrammer: I tried to implement what you suggested, edited the new lines of code into the code in the original question (commented them with //*new*, there are four new lines in there). It still won't work, what seems to be the problem? – user3150201 Jan 01 '14 at 11:35
1

You should wrap the keys.

Create keys[] and if a key pressed change the keys[] don't activate the events like movement:

void keyPressed(){
     if(key==KeyEvent.VK_something)keys[something]=true;
}
void keyReleased(){
     if(key==KeyEvent.VK_something)keys[something]=false;
}

and inside your loop, when you update the game logic, check for key events:

if(keys[up] == true)moveUp();
if(keys[right] == true)rotateRight();

That way both rotate and move will be active at the same time, without cancelling each other.

MoonBun
  • 4,322
  • 3
  • 37
  • 69
  • Thanks I'll try it. By "inside your loop" you mean in the 'game-loop', that's inside Board class? – user3150201 Jan 01 '14 at 11:46
  • You can put it at the start of actionPerformed – MoonBun Jan 01 '14 at 11:47
  • Your approach is problematic because it's not time based but event based, so that it won't update when you don't press any keys. You can change it but now actionPerformed will be enough – MoonBun Jan 01 '14 at 11:49