Bruno Battaglia Bruno Battaglia - 4 months ago 28
Java Question

Keyboard's arrow in JavaFX

It's me again! I have a cannon and for now I'm trying moving it with keyboard's arrows. I don't understand why code doesn't work? Where am I wrong?
Thank you!

public class SchermataGiocoController {

private Parent Menu, Avvio;
private TranslateTransition tt;
private Cannone cannone;
private Aereo aereo;
private Proiettile proiettile;
private RotateTransition rt;

@FXML
private Circle circle;

@FXML
private Button exit;

@FXML
private ImageView cannone_im;

@FXML
private ImageView carro;

@FXML
private AnchorPane SchermataGioco;

@FXML
private ImageView aereo_im;

@FXML
private Button menu;

@FXML
private Button home;

@FXML
void initialize() {
assert exit != null : "fx:id=\"exit\" was not injected: check your FXML file 'SchermataGioco.fxml'.";
assert cannone_im != null : "fx:id=\"cannone_im\" was not injected: check your FXML file 'SchermataGioco.fxml'.";
assert carro != null : "fx:id=\"carro\" was not injected: check your FXML file 'SchermataGioco.fxml'.";
assert SchermataGioco != null : "fx:id=\"SchermataGioco\" was not injected: check your FXML file 'SchermataGioco.fxml'.";
assert aereo_im != null : "fx:id=\"aereo_im\" was not injected: check your FXML file 'SchermataGioco.fxml'.";
assert up != null : "fx:id=\"up\" was not injected: check your FXML file 'SchermataGioco.fxml'.";
assert menu != null : "fx:id=\"menu\" was not injected: check your FXML file 'SchermataGioco.fxml'.";
assert down != null : "fx:id=\"down\" was not injected: check your FXML file 'SchermataGioco.fxml'.";
assert home != null : "fx:id=\"home\" was not injected: check your FXML file 'SchermataGioco.fxml'.";

//creazione di un oggetto Cannone
cannone = new Cannone(129, 96, 0, 340); //Cannone = cannone
//creazione di un oggetto Proiettile
proiettile = new Proiettile(16, 16, 0, 340); //proiettile = bullet
//inizializzazione dei vari metodi
TranslateTransition();
moveUp();
moveDown();
goHome();
}
//Method to change scene and back to home
public void goHome() {
home.setOnAction((ActionEvent event) -> {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Game.class.getResource("/game/view/Avvio.fxml"));

Avvio = (Parent) loader.load();
home.getScene().getWindow().hide();
} catch (IOException ioe) {
ioe.getMessage();
}
Stage stage = new Stage();
stage.setScene(new Scene(Avvio));
stage.show();
});
}
@FXML
public void moveUp() {
cannone_im.getScene().setOnKeyPressed((KeyEvent ke) -> {
if (ke.getCode().equals(KeyCode.RIGHT)) {
rt = new RotateTransition(Duration.millis(100), cannone_im);
if (cannone_im.getRotate() > -70) {
rt.setAxis(Z_AXIS);
rt.setByAngle(cannone_im.getRotate());
rt.setToAngle(cannone_im.getRotate() - 5);
} else {
rt.setToAngle(-70);
}
}
rt.play();
});
}


The error is that root cannot be null. Thanks!

Answer

After the update: your code has several problems.

1) Key events are fired when the Node has focus

Your ImageView will not have focus therefore the KeyEvent is never fired.

Solution: add the listener directly to your Scene.

This answer is a good reference: How to write a KeyListener for JavaFX

2) You should not use setOnKeyReleased

Especially in a game, it is really frustrating if the event just fired when you release the key.

Solution: Use setOnKeyPressed instead.

3) As you call moveUp() in initialize, it should not have the @FXML annotation

The @FXML annotation indicates that you want to use this function as a reference in the FXML file. But this method just creates the listener it is not the listener itself.

Solution: Remove the @FXML annotation from moveUp()

It is related to this question: Lambda functions with FXML in JavaFX8

4) You should ensure that the sceneProperty is not null before attaching the listener

Solution: Listen to the change of the sceneProperty of the ImageView.

The final solution can be something like this:

// The @FXML annotation is removed!
public void moveUp() {       
    cannone_im.sceneProperty().addListener(new ChangeListener<Scene>() {

        @Override
        public void changed(ObservableValue<? extends Scene> observable, Scene oldValue, Scene newValue) {

            if(newValue != null){
                cannone_im.getScene().setOnKeyPressed((KeyEvent ke) -> {
                    if (ke.getCode().equals(KeyCode.RIGHT)) {
                        rt = new RotateTransition(Duration.millis(100), cannone_im);
                        if (cannone_im.getRotate() > -70) {
                            rt.setAxis(Z_AXIS);                    
                            rt.setByAngle(cannone_im.getRotate());
                             rt.setToAngle(cannone_im.getRotate() - 5);
                        } else {                    
                            rt.setToAngle(-70);
                        }
                    }
                    rt.play();
                });
            }
        }
    });
}