352 lines
12 KiB
Java
352 lines
12 KiB
Java
import javafx.application.Application;
|
|
import javafx.application.Platform;
|
|
import javafx.geometry.Insets;
|
|
import javafx.geometry.Pos;
|
|
import javafx.scene.Scene;
|
|
import javafx.scene.control.*;
|
|
import javafx.scene.layout.*;
|
|
import javafx.stage.Stage;
|
|
|
|
public class MainFX extends Application {
|
|
private TextArea logArea;
|
|
private Label heroLabel;
|
|
private Label monsterLabel;
|
|
private Button attackButton, specialButton, healButton, newGameButton;
|
|
private ToggleButton autoToggle;
|
|
private ProgressBar heroHpBar;
|
|
private ProgressBar monsterHpBar;
|
|
|
|
private Held hero;
|
|
private Monster monster;
|
|
|
|
private volatile boolean autoFightRunning = false;
|
|
private Thread autoThread;
|
|
|
|
private int healPotionCount = 3;
|
|
|
|
// entry point
|
|
public static void main(String[] args) {
|
|
System.out.println("Starte JavaFX...");
|
|
launch(args);
|
|
}
|
|
|
|
@Override
|
|
public void start(Stage primaryStage) {
|
|
try {
|
|
primaryStage.setTitle("RPG - JavaFX GUI");
|
|
|
|
VBox leftPane = new VBox(10);
|
|
leftPane.setPadding(new Insets(12));
|
|
leftPane.setPrefWidth(300);
|
|
|
|
Label chooseLabel = new Label("Held erstellen");
|
|
ChoiceBox<String> typeChoice = new ChoiceBox<>();
|
|
typeChoice.getItems().addAll("Krieger", "Schurke", "Elf", "Zauberer");
|
|
typeChoice.setValue("Krieger");
|
|
|
|
// Waffenauswahl (für alle außer Schurke)
|
|
Label weaponLabel = new Label("Waffe wählen:");
|
|
ChoiceBox<String> weaponChoice = new ChoiceBox<>();
|
|
weaponChoice.getItems().addAll("Schwert", "Axt", "Dolch", "Sichel");
|
|
weaponChoice.setValue("Schwert");
|
|
|
|
Label materialLabel = new Label("Material:");
|
|
ChoiceBox<String> materialChoice = new ChoiceBox<>();
|
|
materialChoice.getItems().addAll("Eisen", "Holz", "Knochen", "Stahl");
|
|
materialChoice.setValue("Eisen");
|
|
|
|
TextField nameField = new TextField();
|
|
nameField.setPromptText("Name des Helden");
|
|
|
|
newGameButton = new Button("Neues Spiel");
|
|
newGameButton.setMaxWidth(Double.MAX_VALUE);
|
|
|
|
attackButton = new Button("Angreifen");
|
|
specialButton = new Button("Spezialangriff");
|
|
healButton = new Button("Heiltrank benutzen");
|
|
autoToggle = new ToggleButton("Automatisch kämpfen");
|
|
|
|
for (ButtonBase b : new ButtonBase[] {attackButton, specialButton, healButton, autoToggle}) {
|
|
b.setMaxWidth(Double.MAX_VALUE);
|
|
b.setDisable(true);
|
|
}
|
|
|
|
leftPane
|
|
.getChildren()
|
|
.addAll(
|
|
chooseLabel,
|
|
typeChoice,
|
|
weaponLabel,
|
|
weaponChoice,
|
|
materialLabel,
|
|
materialChoice,
|
|
nameField,
|
|
newGameButton);
|
|
|
|
// Typ-Wahl: Wenn Schurke gewählt ist, Waffenauswahl deaktivieren, Spezial nur für Schurke/Elf
|
|
typeChoice.setOnAction(
|
|
ev -> {
|
|
String t = typeChoice.getValue();
|
|
boolean isRogue = "Schurke".equals(t);
|
|
weaponChoice.setDisable(isRogue);
|
|
materialChoice.setDisable(isRogue);
|
|
specialButton.setDisable(!("Schurke".equals(t) || "Elf".equals(t)));
|
|
});
|
|
|
|
VBox rightPane = new VBox(10);
|
|
rightPane.setPadding(new Insets(12));
|
|
rightPane.setAlignment(Pos.TOP_LEFT);
|
|
|
|
heroLabel = new Label("Held: ---");
|
|
heroHpBar = new ProgressBar(0);
|
|
heroHpBar.setPrefWidth(600);
|
|
|
|
monsterLabel = new Label("Monster: ---");
|
|
monsterHpBar = new ProgressBar(0);
|
|
monsterHpBar.setPrefWidth(600);
|
|
|
|
logArea = new TextArea();
|
|
logArea.setEditable(false);
|
|
logArea.setWrapText(true);
|
|
logArea.setPrefSize(600, 340);
|
|
|
|
// Action buttons über der Anzeige (log)
|
|
HBox actionBox = new HBox(8);
|
|
actionBox.setAlignment(Pos.CENTER_LEFT);
|
|
actionBox.getChildren().addAll(attackButton, specialButton, healButton, autoToggle);
|
|
|
|
rightPane
|
|
.getChildren()
|
|
.addAll(
|
|
heroLabel,
|
|
heroHpBar,
|
|
monsterLabel,
|
|
monsterHpBar,
|
|
actionBox,
|
|
new Label("Spiel-Log:"),
|
|
logArea);
|
|
|
|
Label infoLabel =
|
|
new Label("Tipps: Spezialangriff verursacht mehr Schaden. Heiltränke = begrenzt.");
|
|
|
|
BorderPane root = new BorderPane();
|
|
root.setLeft(leftPane);
|
|
root.setCenter(rightPane);
|
|
root.setBottom(infoLabel);
|
|
BorderPane.setAlignment(infoLabel, Pos.CENTER);
|
|
BorderPane.setMargin(infoLabel, new Insets(8));
|
|
|
|
Scene scene = new Scene(root, 960, 550);
|
|
primaryStage.setScene(scene);
|
|
primaryStage.show();
|
|
|
|
// --- Event Handler ---
|
|
newGameButton.setOnAction(
|
|
e -> {
|
|
String type = typeChoice.getValue();
|
|
String name = nameField.getText().trim();
|
|
if (name.isEmpty()) name = type;
|
|
String weapon = weaponChoice.getValue();
|
|
String material = materialChoice.getValue();
|
|
createNewGame(type, name, weapon, material);
|
|
});
|
|
|
|
attackButton.setOnAction(e -> runOneRound(false));
|
|
specialButton.setOnAction(e -> runOneRound(true));
|
|
healButton.setOnAction(e -> useHealPotion());
|
|
autoToggle.setOnAction(
|
|
e -> {
|
|
if (autoToggle.isSelected()) startAutoFight();
|
|
else stopAutoFight();
|
|
});
|
|
|
|
primaryStage.setOnCloseRequest(
|
|
e -> {
|
|
stopAutoFight();
|
|
Platform.exit();
|
|
System.exit(0);
|
|
});
|
|
|
|
appendLog("Willkommen zum RPG (GUI). Erstelle zuerst einen Helden.");
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
// ---- Ab hier: deine Spiellogik-Methoden ----
|
|
private void createNewGame(String typ, String name, String weaponType, String material) {
|
|
try {
|
|
Waffe weapon = new Waffe(weaponType, material);
|
|
if (typ.equals("Krieger")) {
|
|
hero = new Krieger(name, 30, 6, 1.2);
|
|
} else if (typ.equals("Schurke")) {
|
|
// Waffen in Schurken anders genutzt
|
|
Waffe dolch = new Waffe("Dolch", "stahl");
|
|
Waffe axt = new Waffe("Axt", "stahl");
|
|
hero = new Schurke(name, 24, 5, dolch, axt);
|
|
} else if (typ.equals("Zauberer")) {
|
|
hero = new Zauberer(name, 22, 5);
|
|
} else {
|
|
hero = new Elf(name, 22, 5);
|
|
}
|
|
hero.setWaffe(weapon);
|
|
|
|
monster = generateMonster();
|
|
healPotionCount = 3;
|
|
|
|
appendLog(
|
|
String.format(
|
|
"Neues Spiel gestartet: %s (%s) vs %s HP:%d DMG:%d",
|
|
hero.getName(),
|
|
hero.getTyp(),
|
|
monster.getName(),
|
|
monster.getHp(),
|
|
monster.getDamage()));
|
|
|
|
updateStatusLabels();
|
|
|
|
for (ButtonBase b : new ButtonBase[] {attackButton, specialButton, healButton, autoToggle}) {
|
|
b.setDisable(false);
|
|
}
|
|
|
|
// Spezial nur für Schurke und Elf
|
|
specialButton.setDisable(!("Schurke".equals(typ) || "Elf".equals(typ)));
|
|
|
|
} catch (Exception ex) {
|
|
appendLog("Fehler beim Erstellen des Helden: " + ex.getMessage());
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
|
|
private Monster generateMonster() {
|
|
String[] names = {"Goblin", "Zombie", "Ork", "Skelett", "Troll", "Drache"};
|
|
String name = names[(int) (Math.random() * names.length)];
|
|
int baseHp = 18 + (int) (Math.random() * 10);
|
|
int baseDmg = 3 + (int) (Math.random() * 5);
|
|
Monster m = new Monster(baseHp, baseDmg, name);
|
|
return m;
|
|
}
|
|
|
|
private void runOneRound(boolean special) {
|
|
if (hero == null || monster == null) return;
|
|
if (hero.getHp() <= 0 || monster.getHp() <= 0) return;
|
|
|
|
if (special) {
|
|
// Spezialfähigkeiten nur für Elf (SpeedBoost) und Schurke (Doppelangriff)
|
|
if (hero instanceof Elf) {
|
|
((Elf) hero).speedBoostAktivieren();
|
|
appendLog(hero.getName() + " aktiviert SpeedBoost!");
|
|
hero.angreifen(monster);
|
|
} else if (hero instanceof Schurke) {
|
|
// Spezieller Schurke-Angriff: wechselt zur Axt, führt Angriff aus, dann normaler Angriff
|
|
String msg = ((Schurke) hero).specialAngriff(monster);
|
|
appendLog(msg);
|
|
if (monster.getHp() > 0) {
|
|
// zusätzlich ein normaler Folgeangriff
|
|
hero.angreifen(monster);
|
|
appendLog(hero.getName() + " greift nach dem Spezialangriff erneut an!");
|
|
}
|
|
} else {
|
|
appendLog("Spezialfähigkeit nicht verfügbar für " + hero.getTyp());
|
|
hero.angreifen(monster);
|
|
}
|
|
} else {
|
|
hero.angreifen(monster);
|
|
appendLog(hero.getName() + " greift an!");
|
|
}
|
|
|
|
updateStatusLabels();
|
|
if (monster.getHp() <= 0) {
|
|
appendLog("Monster " + monster.getName() + " besiegt!");
|
|
disableActions();
|
|
return;
|
|
}
|
|
|
|
int mdmg = monster.getDamage();
|
|
hero.setHp(hero.getHp() - mdmg);
|
|
appendLog(monster.getName() + " kontert für " + mdmg + " Schaden!");
|
|
updateStatusLabels();
|
|
|
|
if (hero.getHp() <= 0) {
|
|
appendLog(hero.getName() + " ist gefallen. Spiel Ende.");
|
|
disableActions();
|
|
}
|
|
}
|
|
|
|
private void disableActions() {
|
|
for (ButtonBase b : new ButtonBase[] {attackButton, specialButton, healButton, autoToggle}) {
|
|
b.setDisable(true);
|
|
}
|
|
autoToggle.setSelected(false);
|
|
stopAutoFight();
|
|
}
|
|
|
|
private void useHealPotion() {
|
|
if (healPotionCount <= 0) {
|
|
appendLog("Keine Heiltränke mehr!");
|
|
return;
|
|
}
|
|
hero.setHp(hero.getHp() + 10);
|
|
healPotionCount--;
|
|
appendLog(hero.getName() + " trinkt einen Heiltrank (+10 HP). Verbleibend: " + healPotionCount);
|
|
updateStatusLabels();
|
|
}
|
|
|
|
private void updateStatusLabels() {
|
|
if (hero != null) {
|
|
heroLabel.setText(
|
|
String.format(
|
|
"Held: %s (%s) DMG: %d Heiltränke: %d",
|
|
hero.getName(), hero.getTyp(), hero.getDamage(), healPotionCount));
|
|
double hpFraction = hero.getMaxHp() > 0 ? (double) hero.getHp() / hero.getMaxHp() : 0;
|
|
heroHpBar.setProgress(Math.max(0.0, Math.min(1.0, hpFraction)));
|
|
heroHpBar.setTooltip(new Tooltip(hero.getHp() + " / " + hero.getMaxHp()));
|
|
} else heroLabel.setText("Held: ---");
|
|
|
|
if (monster != null) {
|
|
monsterLabel.setText(
|
|
String.format(
|
|
"Monster: %s HP: %d DMG: %d",
|
|
monster.getName(), monster.getHp(), monster.getDamage()));
|
|
double mhpFraction =
|
|
monster.getMaxHp() > 0 ? (double) monster.getHp() / monster.getMaxHp() : 0;
|
|
monsterHpBar.setProgress(Math.max(0.0, Math.min(1.0, mhpFraction)));
|
|
monsterHpBar.setTooltip(new Tooltip(monster.getHp() + " / " + monster.getMaxHp()));
|
|
} else monsterLabel.setText("Monster: ---");
|
|
}
|
|
|
|
private void appendLog(String text) {
|
|
Platform.runLater(() -> logArea.appendText(text + "\n"));
|
|
}
|
|
|
|
private void startAutoFight() {
|
|
if (autoFightRunning) return;
|
|
autoFightRunning = true;
|
|
appendLog("Auto-Kampf gestartet.");
|
|
autoThread =
|
|
new Thread(
|
|
() -> {
|
|
while (autoFightRunning && hero.getHp() > 0 && monster.getHp() > 0) {
|
|
Platform.runLater(() -> runOneRound(false));
|
|
try {
|
|
Thread.sleep(800);
|
|
} catch (InterruptedException ignored) {
|
|
}
|
|
}
|
|
Platform.runLater(
|
|
() -> {
|
|
autoToggle.setSelected(false);
|
|
appendLog("Auto-Kampf beendet.");
|
|
});
|
|
autoFightRunning = false;
|
|
});
|
|
autoThread.setDaemon(true);
|
|
autoThread.start();
|
|
}
|
|
|
|
private void stopAutoFight() {
|
|
autoFightRunning = false;
|
|
if (autoThread != null) autoThread.interrupt();
|
|
}
|
|
}
|