Search code examples
eventsmenujavafxhandlerscene

JavaFx State change Listener


I am working on an application where I want to implement a menu. I have a GameState and a MainMenu class. Both extends Group. I can't figure out how to write a change listener to the Main.state, so when it changes from .MENU to .GAME the scenes will switch.

Here's is a part of the MainMenu class:

public class MainMenu extends Group {
private final Image background;
private final Rectangle bgRect;
private final int buttonNo = 3;
private MenuButton[] buttons;
private final double xStart = -200;
private final double yStart = 100;
private Group root;
private Scene scene;


public MainMenu () {
    background = new Image(getClass().getResource("mainmenuBg.png").toString());        
    bgRect = new Rectangle(660,660);
    bgRect.setFill(new ImagePattern(background));

    root = new Group();
    scene = new Scene(root, 650, 650);
    scene.setCamera(new PerspectiveCamera());

    root.getChildren().add(bgRect);

    initButtons(root);

    //Start game
    buttons[0].setOnMouseClicked(new EventHandler<Event>() {

        @Override
        public void handle(Event t) {
            Main.state = STATE.GAME;
        }
    });

    //Options
    buttons[1].setOnMouseClicked(new EventHandler<Event>() {

        @Override
        public void handle(Event t) {
            //options menu will come here
        }
    });

    //Exit
    buttons[2].setOnMouseClicked(new EventHandler<Event>() {

        @Override
        public void handle(Event t) {
            Platform.exit();
        }
    });
}
 //...
}

The main class:

public class Main extends Application {
public int difficulty = 1;
GameState gameState;
MainMenu mainMenu;

public enum STATE {
    MENU,
    GAME
}

public static STATE state = STATE.MENU;

@Override
public void start(Stage stage) {  
    stage.resizableProperty().setValue(false);
    stage.setTitle("Main");
    Scene scene = new Scene(new StackPane(), 650, 650);

    stage.setScene(scene);
    stage.show();

    if(Main.state == STATE.MENU)
        enterMainMenu(stage);
    if(Main.state == STATE.GAME)
        enterGameState(stage);


}
//...
}

Any help would be appreciated.


Solution

  • I have succeeded to find a good solution. I have removed the scene field from these classes, and added the super method in the constructors, than added the elements to the class (this.getChildren().addAll(..)).

    Finally, here's my main controller:

    public class Main extends Application {
    public int difficulty = 1;
    public GameState gameState = new GameState(difficulty);
    public MainMenu mainMenu = new MainMenu();;
    StackPane stackPane = new StackPane();
    
    @Override
    public void start(final Stage stage) {  
        stage.resizableProperty().setValue(false);
        stage.setTitle("Main");
        Scene scene = new Scene(stackPane, 650, 650);    
        scene.setCamera(new PerspectiveCamera());
    
        stage.setScene(scene);
        stage.show();
    
        stackPane.getChildren().add(mainMenu);
    
        mainMenu.getStartButton().setOnAction(new EventHandler<ActionEvent>() {
    
            @Override
            public void handle(ActionEvent t) {
                changeScene(gameState);
                try {
                    gameState.startGame();
                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    
    }
    
    public void changeScene(Parent newPage) {
        stackPane.getChildren().add(newPage);
    
      EventHandler<ActionEvent> finished = new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
          stackPane.getChildren().remove(0);
        }
      };
    
      final Timeline switchPage = new Timeline(
        new KeyFrame(Duration.seconds(0), new KeyValue(stackPane.getChildren().get(1).opacityProperty(), 0.0), new KeyValue(stackPane.getChildren().get(0).opacityProperty(), 1.0)),
        new KeyFrame(Duration.seconds(3), finished, new KeyValue(stackPane.getChildren().get(1).opacityProperty(), 1.0), new KeyValue(stackPane.getChildren().get(0).opacityProperty(), 0.0))
      );
    
      switchPage.play();
    }
    }