Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何防止按键被按下时重复动作?_Java_Javafx - Fatal编程技术网

Java 如何防止按键被按下时重复动作?

Java 如何防止按键被按下时重复动作?,java,javafx,Java,Javafx,我试图在一个JavaFX“游戏”中做一个简单的动作,在这个游戏中,每当按下空格键时,一只猪的图像就会向上“跳跃”。下面是关键事件处理程序和动画计时器的代码,我正在使用它们来实际执行操作 密钥处理程序: ArrayList<String> in = new ArrayList<String>(); s.setOnKeyPressed( new EventHandler<KeyEvent>() {

我试图在一个JavaFX“游戏”中做一个简单的动作,在这个游戏中,每当按下空格键时,一只猪的图像就会向上“跳跃”。下面是关键事件处理程序和动画计时器的代码,我正在使用它们来实际执行操作

密钥处理程序:

  ArrayList<String> in = new ArrayList<String>();

    s.setOnKeyPressed(
        new EventHandler<KeyEvent>()
           {

            public void handle(KeyEvent e)
            {
                String code = e.getCode().toString();

                 if ( !in.contains(code) ){
                 in.add( code );                          
                 }

            }
        });

      s.setOnKeyReleased(
        new EventHandler<KeyEvent>()
        {
            public void handle(KeyEvent e)
            {                   
                String code = e.getCode().toString();
                in.remove( code );
            }
        });
如你所见,动画定时器只是让“猪”逐渐沿y轴下落,当按下空格键时,它会稍微向上提升

问题是,如果按住空格键,清管器就会不停地向上飞。我想防止这种情况发生,这样空格键就必须反复敲击,而不仅仅是按住。所以每次按空格键我只想跳一次。我试图解决的问题都没有奏效。我该怎么做?

编辑:我修改了答案。最初的解决方案使用了一个计数器,防止按下的键在一段时间内产生任何影响。不幸的是,这不是这个问题的主题。:)当前的解决方案更直接,只使用一个简单的布尔锁

在回答这个问题之前,这里有一些恼人的提示:我建议使用
Map
而不是
List
来存储关于当前按下哪些键的信息。它将简化代码的可读性,同时提高性能。接下来,创建一个专用对象来存储关于猪的信息(哈哈!)可能是个好主意。最后,使用常量而不是硬编码的文字值是一种很好的做法

另外,请注意,您实际上不需要存储有关是否按下空格键的信息,然后从计时器线程引用它。只有当您希望通过按住空格键来控制清管器时,才需要执行此操作。但是,由于您希望它只在按下空格键时跳转,因此可以直接从处理程序告诉清管器切换到“跳转”状态。当然,这并不能解决您的问题,因为当长时间按住某个键时,
onKeyPressed
处理程序会被重复调用。但我认为这值得一提

现在,回答这个问题。如果您想快速修复当前的解决方案并忽略所有“良好实践”垃圾,请只关注
Pig
类的
jumpLock
字段。诀窍是不断告诉清管器重复跳转,就像你现在做的那样,但要确保清管器只有在
jumpLock
允许的情况下才会服从

注意:以下解决方案假设您将使用固定的时间间隔(如每30毫秒)更新游戏状态。但正如最后指出的,这个解决方案可以很容易地修改为使用基于FPS的计时器

以下类包含将来调整游戏时可能需要更改的常量:

public final class Settings {

    private Settings() {
    }

    public static final double BOOST_VELOCITY = 10.0;
    public static final double GRAVITY = 0.3;
}
这个类代表猪。
x
y
字段存储关于清管器当前位置的信息
velocityX
velocityY
分别是包含关于清管器在X轴和Y轴方向和“速度”信息的向量
jumpLock
是一个简单的布尔标志,它实际上是问题的解决方案。每当用户进行跳转时,此锁定设置为
true
。它将一直保持这种状态,直到它被告知释放锁,这将在用户释放空格键时发生

public final class Pig {

    private double x;
    private double y;
    private double velocityX;
    private double velocityY;
    private boolean jumpLock;

    public Pig() {
        // ...
    }

    public void timeChanged() {
        x += velocityX;
        y += velocityY; 
        velocityY -= Settings.GRAVITY;
    }

    public void jumpBoost() {
        if (!jumpLock) {
            velocityY = Settings.BOOST_VELOCITY;
            jumpLock = true;
        }
    }

    public void releaseLock() {
        jumpLock = false;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }
}

您的处理程序可能是这样的。请注意,
Map
用于存储有关当前按下的键的信息。在这种情况下,它的性能优于
List
。此外,添加
@Override
注释是一种很好的做法,即使在重写抽象方法时也是如此:

final Map<KeyCode, Boolean> keyboard = new HashMap<>();
keyboard.put(KeyCode.SPACE, false);

scene.setOnKeyPressed(
    new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent e) {
            if (e.getCode() == KeyCode.SPACE) {  
                keyboard.put(e.getCode(), true);
                // You could alternately call pig.jumpBoost()
                // directly from this handler and not having to 
                // deal with the 'keyboard' map at all
                // as illustrated with by pig.releaseLock()
                // in the next handler
            }
        }
    });

scene.setOnKeyReleased(
    new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent e) {     
            if (e.getCode() == KeyCode.SPACE) {              
                keyboard.put(e.getCode(), false);
                pig.releaseLock(); // IMPORTANT!!!
            }
        }
    });

希望我没弄错。写这篇文章的时候我几乎睡着了,一开始我误解了这个问题。但我真的需要赢得一些声誉点,才能对一个目前对我很重要的问题发表评论。哈哈D:D

当在AnimationTimer的
handle
方法(在
q-=20
之后)中处理时,可以尝试从
中的
列表中删除“SPACE”,而不是等待
onkeyreased
被触发。现在你要做的是清管器向上移动,直到空格键被释放,这不是你想要的,你只是希望每次新闻都发生一次,对吗?我试过了。出于某种原因,这会导致“跳跃”只上升一点点,然后立即结束,好像删除“空格”会取消动画。这是正确的。非常感谢您花时间提供帮助!这对我帮助很大。好东西。
final Map<KeyCode, Boolean> keyboard = new HashMap<>();
keyboard.put(KeyCode.SPACE, false);

scene.setOnKeyPressed(
    new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent e) {
            if (e.getCode() == KeyCode.SPACE) {  
                keyboard.put(e.getCode(), true);
                // You could alternately call pig.jumpBoost()
                // directly from this handler and not having to 
                // deal with the 'keyboard' map at all
                // as illustrated with by pig.releaseLock()
                // in the next handler
            }
        }
    });

scene.setOnKeyReleased(
    new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent e) {     
            if (e.getCode() == KeyCode.SPACE) {              
                keyboard.put(e.getCode(), false);
                pig.releaseLock(); // IMPORTANT!!!
            }
        }
    });
pig.timeChanged();    
if (keyboard.get(KeyCode.SPACE)) {
    pig.jumpBoost();
}    
// Note that pig.releaseLock() could be called in else 
// branch here and not in the onKeyReleased handler.
// Choose whatever solution suits you best.

// + draw image of the pig on pig.getX() and pig.getY() coordinates