5
\$\begingroup\$

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.

\$\endgroup\$
0

3 Answers 3

6
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

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/)

\$\endgroup\$
1
  • \$\begingroup\$ 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.) \$\endgroup\$ May 23, 2013 at 9:01
1
\$\begingroup\$

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...

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .