I\'m trying to write a game in JavaFX but I\'m having a slight issue with it and that\'s the key listeners getting interrupted by other key presses. I\'m using scene.s
This is similar to this question, though the requirements look slightly different. Similar techniques work, but if you just want to respond to the most-recently-pressed key, you probably need some kind of stack.
This example allows you to move a rectangle around the screen, with the up, down, left, or right cursor keys; only the most recently pressed key that is still down is used.
import java.util.LinkedList;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class KeyStackExample extends Application {
@Override
public void start(Stage primaryStage) {
Rectangle rect = new Rectangle(50, 50, 100, 50);
rect.setFill(Color.SALMON);
Pane pane = new Pane(rect);
Scene scene = new Scene(pane, 800, 600);
final double rectangleHSpeed = 100 ; // pixels per second
final double rectangleVSpeed = 100 ;
final double minX = 0 ;
final double maxX = 800 ;
final double minY = 0 ;
final double maxY = 600 ;
final LinkedList keyStack = new LinkedList<>();
scene.setOnKeyPressed(event -> {
KeyCode code = event.getCode();
if (! keyStack.contains(code)) {
keyStack.push(code);
}
});
scene.setOnKeyReleased(event ->
keyStack.remove(event.getCode()));
final LongProperty lastUpdateTime = new SimpleLongProperty();
final AnimationTimer rectangleAnimation = new AnimationTimer() {
@Override
public void handle(long timestamp) {
if (! keyStack.isEmpty() && lastUpdateTime.get() > 0) {
final double elapsedSeconds = (timestamp - lastUpdateTime.get()) / 1_000_000_000.0 ;
double deltaX = 0 ;
double deltaY = 0 ;
switch(keyStack.peek()) {
case UP:
deltaY = -rectangleVSpeed * elapsedSeconds;
break ;
case DOWN:
deltaY = rectangleVSpeed * elapsedSeconds ;
break ;
case LEFT:
deltaX = -rectangleHSpeed * elapsedSeconds ;
break ;
case RIGHT:
deltaX = rectangleHSpeed * elapsedSeconds ;
default:
break ;
}
double oldX = rect.getTranslateX() ;
double oldY = rect.getTranslateY() ;
rect.setTranslateX(clamp(oldX + deltaX, minX, maxX));
rect.setTranslateY(clamp(oldY + deltaY, minY, maxY));
}
lastUpdateTime.set(timestamp);
}
};
rectangleAnimation.start();
primaryStage.setScene(scene);
primaryStage.show();
}
private double clamp(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}
public static void main(String[] args) {
launch(args);
}
}