处理多次按键忽略重复键

时间:2012-08-07 17:34:21

标签: java swing keypress keylistener keyrelease

我在另一个问题(> How do I handle simultaneous key presses in Java?)的评论部分询问了这个问题,并被要求完全提出一个新问题。

我的问题是,当我创建一个按键的ArrayList时,如果用户按下键,则不会通过keyReleased事件足够快地删除它们。我希望运动与#34; asdf"和北,东,南,西,东北......等。

这是我的两个事件的代码:

@Override
public void keyPressed(KeyEvent e) {
    if(chatTextField.isFocusOwner() == true){
        //do nothing - don't walk
    } else {
        logger.debug("Key Pressed: " + e.getKeyChar());
        lastKey = keysPressed.get(keysPressed.size()-1);

        for (String key : keysPressed){
            if (!key.contains(String.valueOf(e.getKeyChar())) && !lastKey.contains(String.valueOf(e.getKeyChar()))){
                keysPressed.add(String.valueOf(e.getKeyChar()));
                System.out.println("ADDED: " + keysPressed);
            }
        }

        String keysList = keysPressed.toString();
        if (keysList.contains("w")){
            if (keysList.contains("d")){
                requestCharacterMove("NorthEast");
            } else if(keysList.contains("a")){
                requestCharacterMove("NorthWest");
            } else{
                requestCharacterMove("North");
            }
        } else if (keysList.contains("s")){
            if (keysList.contains("d")){
                requestCharacterMove("SouthEast");
            } else if(keysList.contains("a")){
                requestCharacterMove("SouthWest");
            } else{
                requestCharacterMove("South");
            }
        } else if (keysList.contains("d")){
            requestCharacterMove("East");
        } else if (keysList.contains("a")){
            requestCharacterMove("West");
        }
    }
}

@Override
public void keyReleased(KeyEvent e) {
    if(chatTextField.isFocusOwner() == true){
        //do nothing - don't walk
    } else {
        logger.debug("Key Released: " + e.getKeyChar());
        for (String key : keysPressed){
            if (key.contains(String.valueOf(e.getKeyChar()))){
                keysPressed.remove(String.valueOf(e.getKeyChar()));
                System.out.println("REMOVED: " + keysPressed);
            }
        }
    }
}

@Override
public void keyTyped(KeyEvent arg0) {
    // TODO Auto-generated method stub

}

在我通过lastKey(String)变量添加第二张支票之前,创建的金字塔非常庞大。即使进行了第二次检查,列表也会增长,并且几乎总是有两到三个重复。任何有关这方面的帮助都会很棒,因为我的角色正在笨拙地移动。 :(

另外,任何删除重复转换为char,string,arrayList的方法都会很棒,因为我很紧张我使用了太多类型的东西"简单"。

3 个答案:

答案 0 :(得分:4)

您最近可能会慢慢处理事情的观点是完全是许多System.out.println()语句。

你没有得到对角线移动的问题源于你有点错误的检查逻辑 - 而不是明确地检查是否(例如)键A B被按下,只需单独检查它们 - 键A将角色向一个方向移动,B向另一个方向移动。总计(例如),通过移动WEST NORTH,您将有效地移动到NORTHWEST。

您可以使用java.util.BitSet而不是按下的键列表,只需为当前按下的每个键设置位。这也应该大大减少你需要编写的代码量(keyPressed只设置由密钥代码指示的位,keyReleased清除它)。要检查是否按下某个键,请询问BitSet,然后是否设置了代码位。

编辑:使用BitSet而不是列表的示例

public class BitKeys implements KeyListener {

    private BitSet keyBits = new BitSet(256);

    @Override
    public void keyPressed(final KeyEvent event) {
        int keyCode = event.getKeyCode();
        keyBits.set(keyCode);
    }

    @Override
    public void keyReleased(final KeyEvent event) {
        int keyCode = event.getKeyCode();
        keyBits.clear(keyCode);
    }

    @Override
    public void keyTyped(final KeyEvent event) {
        // don't care
    }

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

}

我使示例实现了KeyListener,因此您甚至可以按原样使用它。当您需要知道是否按下某个键时,只需使用isKeyPressed()。您需要决定是否更喜欢原始密钥代码(就像我一样)或者使用关键字符(就像您目前所做的那样)。在任何情况下,您都会看到如何使用BitSet类来记录键的代码量减少到几行:)

答案 1 :(得分:1)

作为替代方案,此game使用数字小键盘通过单次击键实现每个(半)基本方向。默认排列显示在 Design 部分中。可以单独重新分配键以在键盘上的任何位置映射类似的莲座。

答案 2 :(得分:0)

看起来你没有正确处理Java中的线程。任何Java程序都有三个线程(最小)。它们是主程序线程,事件派发线程,还有一个我现在还记不住的。

每当你得到一个事件时,它就会被一个特殊的线程传递给你(我相信它是事件派遣线程,但除此之外)。你不允许在这个线程上做任何事情(这需要时间),这将冻结你的输入并导致你错过事件,使Java看起来没有反应。所以发生的事情是你在java中打破了事件系统。你应该做的是将结果存储在某种缓冲区中,这是你可以期望对事件做的事情,然后按照我的描述进行处理。

[除了: 一个有趣的应用程序是制作一个简单的gui,并在按下按钮调用等待线程5秒钟。你的整个gui都会冻结,直到延迟结束!]

您应该在侧面运行不同的线程(可能是您的主线程)。它将运行某种循环,它控制程序中的帧,每个游戏周期完成一次。每个循环一次,该线程读取存储在输入缓冲区中的结果并处理它们。这背后的理论很简单,但执行可能有点混乱,因为您需要确保没有丢弃任何输入事件或者只读取一次输入事件。无论哪种方式,祝你的游戏好运!