好的,所以我正在尝试使用JavaFX制作一个带有GUI的基于文本的游戏。在我进入真正的游戏循环之前,一切都很顺利。尽管一旦我把代码放进游戏循环中,程序就不会启动。它运行时不会出现错误或异常,但窗口根本不会弹出。当我关闭窗口时,IntelliJ中的所有命令行都显示"进程已完成,退出代码为130",这显然意味着程序已关闭,因为用户按下了Ctrl+C。事实并非如此,因为窗口甚至没有弹出,所以任何用户都不可能点击Ctrl+C来终止程序。所以我的问题是,我该怎么做才能在没有窗口拒绝弹出的情况下,用游戏循环(while循环)运行我的程序。这是我的代码:
package sample;
/**
* Created by Angel on 7/26/16.
*/
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
public class Game {
// Inventory is a class that i made,
// but im sure it has nothing to do with my problem
private Inventory inv = new Inventory();
private String levels;
private Scene scene;
private Label topText;
private Button btn1;
private Button btn2;
private Button btn3;
private boolean gameOn;
public void gameStart(){
// Setting the GUI
// Setting up the window
VBox window = new VBox(210);
// setting up the top text holder.
HBox textHolder = new HBox();
textHolder.setAlignment(Pos.CENTER);
// setting up the label
topText = new Label();
topText.setText("You in a dark room, what do you do?");
// setting up the button holder
HBox buttonHolder = new HBox(50);
buttonHolder.setAlignment(Pos.CENTER);
// setting up the buttons
btn1 = new Button();
btn1.setPrefWidth(260);
btn1.setPrefHeight(30);
btn1.getStyleClass().add("gameButtons");
btn1.setText("1");
btn2 = new Button();
btn2.setPrefWidth(260);
btn2.setPrefHeight(30);
btn2.getStyleClass().add("gameButtons");
btn2.setText("2");
btn3 = new Button();
btn3.setPrefWidth(260);
btn3.setPrefHeight(30);
btn3.getStyleClass().add("gameButtons");
btn3.setText("3");
// finalizing the gui, by putting it all together
textHolder.getChildren().add(topText);
buttonHolder.getChildren().addAll(btn1, btn2, btn3);
window.getChildren().addAll(textHolder, buttonHolder);
// setting up the scene
scene = new Scene(window, 800, 600);
//adding the css script
// adding css script
scene.getStylesheets().add(this.getClass().getResource("game.css").toExternalForm());
// the game loop.
levels = "Storyline";
gameOn = true;
while(gameOn) {
switch (levels) {
case "Storyline":
btn1.setText("search around");
btn2.setText("turn the light on");
btn3.setText("stand in fear");
btn2.setOnAction(e -> levels = "level1");
break;
case "level1":
topText.setText("You turned the light on");
break;
}
}
}
public Scene getScene(){
return scene;
}
}
这不应该是一个游戏循环。单击按钮会触发一个事件。应该在那里处理。没有必要一次又一次地更新按钮文本等等,这就是你目前正在做的。
通过在那里执行循环,您可以阻塞应用程序线程,该线程负责重新绘制和处理用户交互,使其无法完成任务。
重新调整代码以工作基于事件的,即
用户交互(单击按钮)触发ui更新(状态的更改和ui的单个更新)。
例如:
public class Game {
...
public void gameStart(){
...
// setting up the scene
scene = new Scene(window, 800, 600);
// adding css
scene.getStylesheets().add(this.getClass().getResource("game.css").toExternalForm());
setLevel("Storyline");
}
public void setLevel(String newLevel) {
// TODO: integrate gameOn value
if (newLevel != null && !newLevel.equals(levels)) {
levels = newLevel;
switch (levels) {
case "Storyline":
btn1.setText("search around");
btn2.setText("turn the light on");
btn3.setText("stand in fear");
// user interaction triggers setting the level
btn2.setOnAction(e -> setLevel("level1"));
break;
case "level1":
topText.setText("You turned the light on");
break;
}
}
}
...
}
附加建议:不要将级别表示为String
,将其表示为实现接口的实例:
public interface Level {
// do updates for level start on game
void updateGameLevelStart(Game game);
// cleanup code e.g. unregistering event handlers...
void updateGameLevelEnd(Game game);
}
这将允许您将levels
的类型更改为Level
,并简化更新:
public void setLevel(Level newLevel) {
if (!Objects.equals(levels, newLevel)) {
if (levels != null) {
// cleanup old level
levels.updateGameLevelEnd(this);
}
levels = newLevel;
if (newLevel != null) {
// start new level
newLevel.updateGameLevelStart(this);
}
}
}
这当然需要您使ui的相关部分可供Level
实现访问。