我试图在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轴,当按下空格键时,它会向上轻微提升。
问题在于,如果空格键被按住,猪只会不停地向上飞行而不会停止。我想要防止这种情况,以便必须反复敲击空格键而不是按住它。所以我只想要一个跳跃&#39;按空格键按。我尝试解决它的任何事情都没有奏效。我怎么能这样做?
答案 0 :(得分:3)
编辑: 我重写了答案。原始解决方案使用计数器,该计数器防止按下的按键在一段时间内受到任何影响。不幸的是,这不是这个问题的内容。 :)当前的解决方案更直接,只使用一个简单的布尔锁。
在回答问题之前,这里有一些令人讨厌的提示:我建议使用Map<KeyCode, Boolean>
代替List<String>
来存储有关当前按下的键的信息。它将在可读性方面简化您的代码,同时提高性能。接下来,创建一个专门的对象来存储有关猪的信息(哈哈!)可能是一个好主意。最后,使用常量而不是硬编码的文字值是一种很好的做法。
另外,请注意,您实际上并不需要存储有关是否按空格键的信息,然后从计时器线程中引用它。只有当你想通过握住空格键来控制猪时,才需要这样做。但是因为你只想在按下空格键时跳转它,你可以告诉猪切换到&#34;跳跃&#34;直接从处理程序状态。当然,这不会解决您的问题,因为在持有较长一段时间的密钥时会重复调用onKeyPressed
处理程序。但我认为值得一提。 :)
现在,回答这个问题。如果您想快速修改当前的解决方案并忽略所有&#34;良好实践&#34;废话,只关注jumpLock
类的Pig
字段。诀窍是不断告诉猪像你现在一样反复跳跃,但要确保猪只在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
是包含有关方向和&#34;速度&#34;的信息的向量。猪的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()
方法,并在该方法中将其与必要的内容相乘
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