繁体   English   中英

如何防止按键被重复操作?

[英]How to prevent repeated actions from a key being held down?

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

关键处理程序:

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

动画计时器:

   new AnimationTimer()
{
    double q = 200;
    public void handle(long currentNanoTime)
    {
        double t = (currentNanoTime - startNanoTime) / 4000000.0;    

       if(in.contains("SPACE")){

            q -= 20;

        }

        double y = q + t;

        if(y >= 520){
            gc.drawImage(background1, 0, 0, 1160, 740);
            gc.drawImage(pig, 90, 520, 125, 100);

        }else{
        gc.drawImage(background1, 0, 0, 1160, 740);
        gc.drawImage(pig, 90, y, 125, 100);
        }

    }
}.start();

因此,你可以看到我有动画计时器只是让'猪'逐渐从y轴下降,当按下空格键时,它会向上略微提升。

问题是,如果空格键被按住,猪只会不停地向上飞行而不停止。 我想要防止这种情况,以便必须反复敲击空格键而不是按住它。 所以我想要每个空格键按下一个'跳'。 我试图解决的任何事情都没有奏效。 我怎样才能做到这一点?

编辑: 我重写了答案。 原始解决方案使用计数器,该计数器防止按下的按键在一段时间内受到任何影响。 不幸的是,这不是这个问题的内容。 :)当前的解决方案更直接,只使用一个简单的布尔锁。

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

另外,请注意您实际上不需要存储有关是否按下空格键的信息,然后从计时器线程中引用它。 只有当你想通过握住空格键来控制猪时,才需要这样做。 但是因为你只想在按下空格键时跳转它,你可以告诉猪直接从处理程序切换到“跳转”状态。 当然,这不会解决您的问题,因为在持有较长一段时间的密钥时会重复调用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;
}

这个类代表猪。 xy字段存储有关猪当前位置的信息。 velocityXvelocityY分别是包含关于猪在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<KeyCode, Boolean>用于存储有关当前按下的键的信息。 在这种情况下,它比List<String>表现更好。 即使重写抽象方法,添加@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!!!
            }
        }
    });

最后,必须重复执行以下代码片段。 此解决方案假设此代码将在每30毫秒的固定时间间隔内执行。 如果您使用的是基于FPS的计时器(意味着执行之间会有不规则的间隔),您应该将从上一次更新过去的时间作为参数传递给timeChanged()方法,并在该方法timeChanged()其与必要的内容相乘。

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

希望我做对了。 我写这篇文章时几乎睡着了,最初误解了这个问题。 但我真的需要获得一些声望点才能对一个对我来说很重要的问题发表评论。 哈哈! :d:d

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM