keyPressed event slow on first repeat

冷暖自知 提交于 2020-01-04 04:27:09

问题


Okay so I am sorry for this being a really weird question but it is driving me insane.

I handle my WASD movement for my game via:

Action ClassWASDKeyPressed = new ClassWASDKeyPressed();
Action ClassWASDKeyReleased = new ClassWASDKeyReleased();
BitKeys movementBitKeys = new BitKeys(); //for WASD movement key pressed/releases

//pressed
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "wButtonPress");
theDesktop.getActionMap().put("wButtonPress", ClassWASDKeyPressed);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "aButtonPress");
theDesktop.getActionMap().put("aButtonPress", ClassWASDKeyPressed);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "sButtonPress");
theDesktop.getActionMap().put("sButtonPress", ClassWASDKeyPressed);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "dButtonPress");
theDesktop.getActionMap().put("dButtonPress", ClassWASDKeyPressed);
//released
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "wButtonRelease");
theDesktop.getActionMap().put("wButtonRelease", ClassWASDKeyReleased);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"), "aButtonRelease");
theDesktop.getActionMap().put("aButtonRelease", ClassWASDKeyReleased);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"), "sButtonRelease");
theDesktop.getActionMap().put("sButtonRelease", ClassWASDKeyReleased);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "dButtonRelease");
theDesktop.getActionMap().put("dButtonRelease", ClassWASDKeyReleased);

Here are the two Action classes:

class ClassWASDKeyPressed extends AbstractAction {
    private static final long serialVersionUID = 1L;

    public void actionPerformed(ActionEvent e) {
        if (chatTextField.isFocusOwner() == false){
            if (e.getActionCommand().equals("w")){
                keyPressed(87);
            } else if(e.getActionCommand().equals("a")){
                keyPressed(65);
            } else if(e.getActionCommand().equals("s")){
                keyPressed(83);
            } else if(e.getActionCommand().equals("d")){
                keyPressed(68);
            }
        }
    }
}

class ClassWASDKeyReleased extends AbstractAction {
    private static final long serialVersionUID = 1L;

    public void actionPerformed(ActionEvent e) {
        if (chatTextField.isFocusOwner() == false){
            if (e.getActionCommand().equals("w")){
                keyReleased(87);
            } else if(e.getActionCommand().equals("a")){
                keyReleased(65);
            } else if(e.getActionCommand().equals("s")){
                keyReleased(83);
            } else if(e.getActionCommand().equals("d")){
                keyReleased(68);
            }
        }
    }
}

And here is the logic for this:

public void keyPressed(int e) {
    long endTime = System.nanoTime();
    long elapsedTime = endTime - startTime;
    double elapsedTimeSeconds = (double)elapsedTime / 1000000000.0;

    if (elapsedTimeSeconds < .125){ //let them move 8 times a second
        logger.info("KeyPressed (QUICK): " + elapsedTimeSeconds);
    } else {
        logger.info("KeyPressed (VALID): " + elapsedTimeSeconds);
        //logger.debug("Key Pressed: " + e.getKeyChar());  //FOR TROUBLESHOOTING
        movementBitKeys.keyPressed(e);
        //movementBitKeys.showKeyList();  //FOR TROUBLESHOOTING

        if (movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
            requestCharacterMove("North");
        }
        if (movementBitKeys.isKeyPressed(87) && movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
            requestCharacterMove("NorthEast");
        }
        if (movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && movementBitKeys.isKeyPressed(65)){
            requestCharacterMove("NorthWest");
        }
        if (!movementBitKeys.isKeyPressed(87) && movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
            requestCharacterMove("East");
        }
        if (!movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
            requestCharacterMove("South");
        }
        if (!movementBitKeys.isKeyPressed(87) && movementBitKeys.isKeyPressed(68) && movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
            requestCharacterMove("SouthEast");
        }
        if (!movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && movementBitKeys.isKeyPressed(83) && movementBitKeys.isKeyPressed(65)){
            requestCharacterMove("SouthWest");
        }
        if (!movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && movementBitKeys.isKeyPressed(65)){
            requestCharacterMove("West");
        }
        startTime = endTime;
    }
}

public void keyReleased(int e) {
    //logger.debug("Key Released: " + e.getKeyChar());  //FOR TROUBLESHOOTING
    movementBitKeys.keyReleased(e);
    //movementBitKeys.showKeyList();  //FOR TROUBLESHOOTING
}

public void keyTyped(int e) {
    // not used - but in case I ever want it
}

Also the BitSet class:

package com.jayavon.game.helper;

import java.util.BitSet;

public class BitKeys{

    private BitSet keyBits = new BitSet(256);

    public void keyPressed(final int keyCode) {
        keyBits.set(keyCode);
    }

    public void keyReleased(final int keyCode) {
        keyBits.clear(keyCode);
    }

    public void keyTyped(final int keyCode) {
        // don't care
    }

    public boolean isKeyPressed(final int keyCode) {
        return keyBits.get(keyCode);
    }

    public void showKeyList(){
        System.out.println(keyBits.toString());
    }

}

My problem is when you hold down one of the movement keys between the first and second 'movement' is much longer than the required .125 millisecond wait. Here is some sample data:

Set 1:

6059 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 2.567790275

6620 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.560479937

6670 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.0504469 6710 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.09360516 6750 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.129943376

6791 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.04009505 6821 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.07098997 6851 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.102378686 6902 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.152006677

Set 2:

9690 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 2.03802468

10272 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.582025645

10322 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.054749323 10342 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.069890042 10372 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.100790212 10412 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.141337411

10462 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.049483458 10462 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.049720381 10512 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.098888524 10542 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.128729361

And now time for the question. Obviously the first time you move the elapsed time is huge depending on how long, so that makes sense. What I dont get is why the second 'movement' is around .5 instead of closer to .125. As you can see from the data the third and fourth steps are firing so fast while holding down the key that they are less than .125.

Can anyone help me out with this in any way? Any suggestions to improve my code in any way would be tremendous help indeed. Milliseconds count.


回答1:


Here is how I solved this due to the tremendous help of @aioobe.

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    public void run() {
        checkKeyStrokes();
    }
}, 0, 0135);

public void checkKeyStrokes(){
    if (movementBitKeys.isKeyPressed(87)){ //w
        keyPressed(87);
    }
    if (movementBitKeys.isKeyPressed(65)){ //a
        keyPressed(65);
    }
    if (movementBitKeys.isKeyPressed(83)){ //s
        keyPressed(83);
    }
    if (movementBitKeys.isKeyPressed(68)){ //d
        keyPressed(68);
    }
}

Hope this can be of help to others!!!




回答2:


After analyzing your code - a quick response from me

  • When a key is pressed to quick its not regognized by your movementBitKeys (not valid) This could be a problem. When you press the keys quickly e.g "s" followed by an "w" than "a".

"s" is valid (move south) - move south

(release "s" - do nothing)s

"w" is invalid (to quick)

"a" is valid (move east) -> move east -> this is wrong - should be NorthEast

Another suggestion of me. Currently you use two timers. One for elapsedTimeInSeconds and one Timer to control keys which were pressed.

This can be done in one process

class ClassWASDKeyPressed extends AbstractAction {
  private static final long serialVersionUID = 1L;

  public void actionPerformed(ActionEvent e) {
    if (chatTextField.isFocusOwner() == false){
        if (e.getActionCommand().equals("w")){
            movementBitKeys.keyPressed(87);
        } else if(e.getActionCommand().equals("a")){
            movementBitKeys.keyPressed(65);
        } else if(e.getActionCommand().equals("s")){
            movementBitKeys.keyPressed(83);
        } else if(e.getActionCommand().equals("d")){
            movementBitKeys.keyPressed(68);
        }
    }
  }

}

And a change in TimerTask

Timer timer = new Timer();
timer.schedule(new TimerTask() {
  public void run() {
    move(movementBitKeys); // instead of keypressed - without elapsedTimeSeconds  
  }
}, 0, 0125);



回答3:


If you're holding a key down then there is a timer that waits before sending repeat events. This sounds very similar to the question posted here Eliminating Initial keypress delay and Fixing delay issue in java keypress action

Why not just take the approach of assuming that when you receive a keyPressed event that the key is down until you get a keyReleased. So simply don't rely on the system generating the event for you. Have your own timer that when you've received a keyPressed event and no keyRelease that it requests at your required interval that the character moves in the key pressed direction. When you receive a keyRelease simply stop the timer.



来源:https://stackoverflow.com/questions/13043229/keypressed-event-slow-on-first-repeat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!