Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am working on a game using only the swing and awt packages. Note I can only use the default Java libs. Meaning I have to use KeyListener. I have imported KeyListener properly, however, it is still relatively buggy. Here is a snippet of my code.

p is for Player class, I am going to set x and y to private, however, this is for simplicity

public void keyPressed(KeyEvent e) {
    keys[e.getKeyCode()] = true;

    if(keys[KeyEvent.VK_W] || keys[KeyEvent.VK_UP]){
        p.y += 5;
    }

    if(keys[KeyEvent.VK_S] || keys[KeyEvent.VK_DOWN]){
        p.y -= 5;
    }

    if(keys[KeyEvent.VK_A] || keys[KeyEvent.VK_LEFT]){
        p.x += 5;
    }

    if(keys[KeyEvent.VK_D] || keys[KeyEvent.VK_RIGHT]){
        p.x -= 5;
    }
}

public void keyReleased(KeyEvent e) {
    keys[e.getKeyCode()] = false;
}

public void keyTyped(KeyEvent e) {
}

Sadly this code has a lag to it. Of a second... Also, the motion is not a fluid... However, I don't want you to fix my code. Rather, what other methods are more clean? As well, I have worked with engines, they all seem to have an: isDown, PressedOnce, Released(However, I know how to implement this), ect.

share|improve this question
    
+1 for a very common, but unasked question. –  Hele May 23 '13 at 2:28
add comment

4 Answers

up vote 3 down vote accepted

Possible cause : From your code, no visible sources of lag are present. The lag may come from the way they are accessed from the game loop thread. Dont forget, the variables have to be synchronized, or you have to use locks for your app to be thread safe.

The lag you experienced may be from the fact that you increment the x and y by 5 each. I am guessing that this makes them move by 5 pixels. Maybe if you change it to something like 2, you will see smoother graphics.

Suggested format: I suggest you try to implement something like the following for maximum efficiency and thread safety.

Suggested structure

Explanation :

1. The InputManager class detects the input and stores them in local variables inside
the InputManager class itself.

2. At some point in the game loop, a method (Maybe getProcessedData()) is called that
is inside the InputManager class that processes the data stored in it and returns.

3. The recieved information is used by the game loop.

4. Don't directly modify the original flags(The ones in the game loop) as is may lead
to unstability.

Additional : Another possible source of lag may be that you are processing heavily in the game loop. Try moving heavier processes to new threads.

Experience : Designing a multi-threaded platformer using swing. Pretty similar to yours.

share|improve this answer
add comment

Your problem is that you are doing the update logic in keyPressed() method.

When you press a key, AWT will call this method once. After a delay (typically 250-1000 milliseconds) it starts calling this method again repeatedly with a smaller delay (typically 30-400 milliseconds). When the key is released, this repetition stops and keyReleased() method is called. In Windows these delays can be controlled from Keyboard properties inside Control Panel. If you hold down multiple keys simultaneously, the repetition events are sent only for one of the keys.

What you should do is to update only the state of the keys in the event handlers and process the movement outside those. With your keys array you are already almost there. Change your code to the following:

public void keyPressed(KeyEvent e) {
    keys[e.getKeyCode()] = true;
}

public void keyReleased(KeyEvent e) {
    keys[e.getKeyCode()] = false;
}

public void keyTyped(KeyEvent e) {
}

public void update() {
    if(keys[KeyEvent.VK_W] || keys[KeyEvent.VK_UP]){
        p.y += 5;
    }

    if(keys[KeyEvent.VK_S] || keys[KeyEvent.VK_DOWN]){
        p.y -= 5;
    }

    if(keys[KeyEvent.VK_A] || keys[KeyEvent.VK_LEFT]){
        p.x += 5;
    }

    if(keys[KeyEvent.VK_D] || keys[KeyEvent.VK_RIGHT]){
        p.x -= 5;
    }
}

You need to call update() repeatedly, once per "frame". Where you should call this method depends on the rest of your code, but typically it's one of:

  • A busy loop where you also trigger rendering
  • Another thread (in which case you need proper synchronization)
  • Paint method, if you let AWT to handle your game loop

You also need to consider timing so that either this method is called with a constant rate or the implementation of update can handle variable time steps. (http://gafferongames.com/game-physics/fix-your-timestep/)

share|improve this answer
    
Exactly. If the game does not use some kind of timer, how could there even be a fluent motion? Key events are not a replacement for a timer. (Note: use javax.swing.Timer, not java.util.Timer, so you don't have to write code for synchronizing with Swing.) –  Viliam Búr May 23 '13 at 9:01
    
Thanks, I don't know if you know how to implement isDown, PressedOnce, Released, etc...? Like I see in many engines. –  Nathan Hatch-Martinez May 23 '13 at 17:23
add comment

I take it that you are keeping an array or an ArrayList, maybe of booleans, that records key states and have some key listeners that modify that. It's hard to see what else, given the limited snippet of code.

Just make your game loop, thread, etc implement the KeyListener interface, unless that is that what you are doing. I think the motion being fluid or not would depend on the rate of increment and how fast the program responded to the input, etc. For best results you would want the player to keep moving if the key is still pressed, and only stop if the key is released. Instead of moving on press/release, you could have a boolean indicating whether the player is moving that is set to true when -key pressed- and false when -key released- and the movement is handled elsewhere as long as key pressed is true. Come to think of it, that would probably help my pong game a bit...

share|improve this answer
add comment

One problem I see with this code, is that it doesn't check if the keycode is in range. I usually make my boolean array to be 65,536 (216 or 2 bytes). Then in the onPressed method, I check if the code is in range. If it is, I set that code to true. This is how I usually code my KeyListener onPressed method:

public void onPressed(KeyEvent e)
{
    int code = e.getKeyCode();
    if(code >= 0 && code < keys.length)
    {
        keys[code] = true;
    }
}

Of course, onReleased is the same, except you are setting the key to false. You will notice I haven't included my player movement code. I recommend you put this in the update loop. If you aren't already updating your game based on time, I recommend you read this thread on game loops. The reason you should update the position in the gameloop, is because you need to detect for collision while you do movement. Since you have the keys array, you just check for keys[KeyEvent.VK_<insert key>]. Make sure you also read Hele's answer.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.