keyPressed事件在第一次重复时变慢

时间:2012-10-24 04:55:16

标签: java events keypress bitset

好的,我很抱歉这是一个非常奇怪的问题,但它让我疯了。

我通过以下方式为我的游戏处理我的WASD运动:

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

以下是两个Action类:

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);
            }
        }
    }
}

以下是这个的逻辑:

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
}

BitSet类:

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());
    }

}

我的问题是当你按住第一个和第二个'运动'之间的一个运动键时,比所需的.125毫秒等待要长得多。以下是一些示例数据:

设置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

设置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

现在是问题的时候了。显然,第一次移动经过的时间很长,取决于多长时间,所以这是有道理的。我没有得到的是为什么第二个'运动'在.5左右而不是接近.125。正如你从数据中看到的那样,第三步和第四步的触发速度非常快,同时按下它们小于.125的键。

任何人都可以帮助我解决这个问题吗?任何以任何方式改进我的代码的建议都将是巨大的帮助。毫秒数。

3 个答案:

答案 0 :(得分:3)

由于@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);
    }
}

希望这对别人有帮助!!!

答案 1 :(得分:3)

在分析您的代码后 - 我的快速回复

  • 当按下某个键以快速移动时,您的运动无法识别(无效) 这可能是个问题。当您快速按下键时,例如“s”后跟“w”而不是“a”。

“s”有效(向南移动) - 向南移动

(释放“s” - 什么都不做)s

“w”无效(快速)

“a”有效(向东移动) - &gt;向东移动 - &gt;这是错误的 - 应该是NorthEast

我的另一个建议。 目前您使用两个计时器。一个用于elapsedTimeInSeconds,一个用于控制按下的键。

这可以在一个过程中完成

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);
        }
    }
  }

}

TimerTask的改变

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

答案 2 :(得分:2)

如果您按住某个键,则会有一个计时器在发送重复事件之前等待。这听起来与此处发布的问题Eliminating Initial keypress delayFixing delay issue in java keypress action

非常相似

为什么不采取假设当你收到keyPressed事件时密钥关闭直到你获得keyReleased的方法。所以根本不要依赖为您生成事件的系统。拥有自己的计时器,当你收到一个keyPressed事件并且没有keyRelease时它会按照你所需的间隔请求角色按下按键方向。当你收到钥匙时,请简单地停止计时器。