2

I am creating a JavaFX application about a game where two armies with units fight until one army wins. My wish is to make the GUI have a label which updates every second to inform the user about the most recent event (for instance: "Red attacks Blue" then "Blue attacks Red"). The problem is my method which simulates the battle is too fast - everything gets executed and finished in milliseconds unless I use Thread.sleep, but using it causes the JavaFX program to freeze and not respond until the method is done. What alternatives from Thread.sleep can I use to give me the desired result, and is it possible to implement the solution directly into the simulate() method?

Current code for my battle simulation:

public Army simulate() {
    Army winner = null;
    while(armyOne.hasUnits() || armyTwo.hasUnits()) {
        if(!armyOne.hasUnits()) {
            winner = this.armyTwo;
            return winner;
        }
        else if(!armyTwo.hasUnits()) {
            winner = this.armyOne;
            return winner;
        }

        Unit attackerOne = armyOne.getRandom();
        Unit defenderOne = armyOne.getRandom();
        Unit attackerTwo = armyTwo.getRandom();
        Unit defenderTwo = armyTwo.getRandom();

        attackerOne.attack(defenderTwo);
        if(defenderTwo.getHealth() <= 0) {
            recentEvent = attackerOne.getName() + " attacks " + defenderTwo.getName() + ", killing them!";
            System.out.println(recentEvent);
            armyTwo.remove(defenderTwo);

            //Program gets put to sleep for 2 seconds
            try {
                Thread.sleep(2000);
            } catch (InterruptedException exception) {
                Thread.currentThread().interrupt();
            }
        } else {
            recentEvent = attackerOne.getName() + " attacks " + defenderTwo.getName() + ", leaving them at "
                    + defenderTwo.getHealth() + " HP!";
            System.out.println(recentEvent);

            //Program gets put to sleep for 2 seconds
            try {
                Thread.sleep(2000);
            } catch (InterruptedException exception) {
                Thread.currentThread().interrupt();
            }
        }
        if(!armyTwo.hasUnits() && armyOne.hasUnits()) {
            winner = this.armyOne;
            return winner;
        }

        attackerTwo.attack(defenderOne);
        if(defenderOne.getHealth() <= 0) {
            recentEvent = attackerTwo.getName() + " attacks " + defenderOne.getName() + ", killing them!";
            System.out.println(recentEvent);
            armyOne.remove(defenderOne);

            //Program gets put to sleep for 2 seconds
            try {
                Thread.sleep(2000);
            } catch (InterruptedException exception) {
                Thread.currentThread().interrupt();
            }
        } else {
            recentEvent = attackerTwo.getName() + " attacks " + defenderOne.getName() + ", leaving them at "
                    + defenderOne.getHealth() + " HP!";
            System.out.println(recentEvent);

            //Program gets put to sleep for 2 seconds
            try {
                Thread.sleep(2000);
            } catch (InterruptedException exception) {
                Thread.currentThread().interrupt();
            }
        }
        if(!armyOne.hasUnits() && armyOne.hasUnits()) {
            winner = this.armyTwo;
            return winner;
        }
    }
    return winner;
}

Code where I handle the "start battle" button in Controller which uses the method:

//Handling "Start battle" Button event.
    startBattleButton.setOnAction(event -> {
        Battle battle = new Battle(leftArmy, rightArmy, terrainBox.getValue());
        Army winner = battle.simulate();
        if(winner.equals(leftArmy)) {
            winnerArmyLabel.setText(winner.getName() + " wins!");
            leftUnitAmount.setText("Units: " + winner.getAllUnits().size());
            rightUnitAmount.setText("Units: 0");
            resetBattleButton.setVisible(true);
            startBattleButton.setDisable(true);
        }

        if(winner.equals(rightArmy)) {
            winnerArmyLabel.setText(winner.getName() + " wins!");
            rightUnitAmount.setText("Units: " + winner.getAllUnits().size());
            leftUnitAmount.setText("Units: 0");
            resetBattleButton.setVisible(true);
            startBattleButton.setDisable(true);
        }
    });

0 Answers0