Bifz
Bifz

Reputation: 403

Waiting for Sub Tasks to Finish in JavaFX

I am trying to create a simple game using JavaFX. The game consists in a main game and sub-games, which the player may have to play, depending on the result of the main game. In the end, the main game has to update it's state (p.e.: score) depending on the sub-games result.

I made a simplified and generalized version of how I have implemented the game logic:

Result play(Player p) {
    Result r = p.play(this);
    for(SubGame game : r.getSubGames())
    {
        p.play(game);
    }
    update(r);
    return r;
}

This game works perfectly in the terminal, since it has a linear execution. But using JavaFX (implemented in the Player), I cannot control the flow of the program properly, because of the game loop.

I have followed this tutorial to handle multiple screens for the main game and sub-games. The Player class can successfully change the screen to a sub-game, using the handler. But the update no longer waits for the sub-games to be played, and this function returns while the player is mid-game.

I am trying to keep the game logic separate from UI, so changes to the code showed above shouldn't be dependent on the interface framework.

Any help?

Upvotes: 0

Views: 400

Answers (1)

James_D
James_D

Reputation: 209553

Use an event-driven approach, setting the values of observable properties, and responding when they change.

For example, you might encapsulate the state of the game with

public class GameState {

    private ObservableList<SubGame> currentGames = FXCollections.observableArrayList();

    public ObservableList<SubGame> getCurrentGames() {
        return currentGames();
    }

    private ReadOnlyObjectWrapper<SubGame> currentGame = new ReadOnlyObjectProperty<>();

    public ReadOnlyObjectProperty<SubGame> currentGameProperty() {
        return currentGame.getReadOnlyProperty() ;
    }

    public final SubGame getCurrentGame() {
        return currentGameProperty().get();
    }

    public GameState() {
        // initialize sub game list...
    }

    public void nextGame() {
        int index = currentGames.indexOf(currentGame.get());
        if (index < currentGames.size() - 1) {
            currentGame.set(currentGames.get(index + 1));
        }
    }

    public void start() {
        currentGame.set(currentGames().get(0));
    }

    public boolean hasMoreGames() {
        return currentGames.indexOf(currentGame.get()) < currentGames.size() - 1 ;
    }
}

And similarly you might have some observable state in your SubGame class:

public class SubGame {

    private final BooleanProperty finished = new SimpleBooleanProperty();

    public BooleanProperty finishedProperty() {
        return finished ;
    }

    public final boolean isFinished() {
        return finishedProperty().get();
    }

    public final void setFinished(boolean finished) {
        finishedProperty().set(finished) ;
    }

    // ...
}

Now your game logic is just implemented with listeners:

void play(Player p) {
    Result r = p.play(this);
    GameState gameState = new GameState();
    gameState.currentGameProperty().addListener((obs, oldGame, newGame) -> {
        newGame.finishedProperty().addListener((obs, wasFinished, isNowFinished) -> {
            if (isNowFinished) {
                // maybe update score etc based on state of newGame...
                if (gameState.hasMoreGames()) {
                    gameState.nextGame();
                } else {
                    // logic here for "all games are finished...
                }
            }
        });
    });
    gameState.start();
}

Obviously the details of how you implement this depend on your requirements etc, but this general approach should work for anything you need.

Upvotes: 1

Related Questions