我一直在做一个小冒险游戏作为我的AP Java
课程的最后一个项目,我已经尝试实现我为{{1}所做的课程了。我使用JavaFX
构建的GUI。
但由于某种原因,GUI拒绝在Adventure类中识别我的方法Scene Builder
,它基本上启动了整个事情。 GUI已启动,但无法正确显示在startAdventure()
中显示的内容。
startAdventure()
似乎根本没有被调用,导致空指针异常,因为startAdventure()
应该在GUI中操纵文本区域等。
如果我没有提供足够的信息,不了解建议等,我会提前道歉。在编码方面我有点挑战,而且我在这个网站上发布内容我是全新的。
以下是startAdventure()
在Adventure类中的开头(text和inputText是我的startAdventure()
文件中正确初始化的变量,它是使用AdventureGUI.fxml
生成的):
Scene Builder
以下是我的主要课程的外观:
public void startAdventure()
{
//welcome user
text.setText("Welcome to the land of euphoria!" + "\n");
//gets users name
text.appendText("What's your name?" + "\n");
p.playerName = inputText.getText();
text.appendText("Welcome, " + p.playerName + "\n");
//sets start location
p.setNewLoc("START");
如果它正常工作,GUI将启动并在文本区域内,它将显示以“欢迎来到兴奋之地!”开头的文本。
但是,在目前的状态下,GUI会启动,文本区域根本没有文字。
再一次,对这里的一切都是新手,所以如果您认为还有其他东西需要我展示以协助建议过程,请立即告诉我。
编辑:当我尝试更改game.startAdventure()所在的顺序时,通过将其放在start方法中的primaryStage.show()之前,发生了很长的异常列表。 以下是我所做的改变:
public class RunAdventure extends Application
{
@Override
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("AdventureGUI.fxml"));
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.setTitle("Adventure");
primaryStage.show();
}
public static void main(String[] args)
{
Adventure game = new Adventure();
launch(args);
game.startAdventure();
}
} //end class
以下是发生的例外情况:
@Override
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("AdventureGUI.fxml"));
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.setTitle("Adventure");
Adventure game = new Adventure();
game.startAdventure();
primaryStage.show();
}
我还应该提到Adventure类也可以作为控制器
编辑(5月20日):好的,我已经把大部分工作都放在了我的程序中,但我现在遇到了一个新问题。在我的冒险中,我有一个功能,允许玩家在各个怪物的战斗中,如果他们在一个给定的位置。我的问题是,一旦我到达我的程序中的这个位置,该程序停止响应。在做了一些调试后,我发现它是一个while循环,我在doBattle()方法中执行所有操作,而player.isAlive和enemy.isAlive。唯一的问题是,一旦我移除了while循环,程序只是在怪物死亡或玩家死亡之后直接跳转,而它应该让你选择是否反复攻击怪物,直到任一实体是死的。我知道我在这个问题上填写了太多东西,但我不知道还有什么地方可以提出来,到目前为止,我得到了大家的支持。我不能够感谢你们,但我不知道如何自己解决这个问题。 这是doBattle()方法的代码:
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:894)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:56)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:158)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at Classwork.FinalExamProject.Adventure.startAdventure(Adventure.java:102)
at Classwork.FinalExamProject.RunAdventure.start(RunAdventure.java:24)
at com.sun.javafx.application.LauncherImpl$8.run(LauncherImpl.java:837)
at com.sun.javafx.application.PlatformImpl$7.run(PlatformImpl.java:335)
at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
答案 0 :(得分:2)
(某些)出错的地方以及如何解决这些问题
按照编码,直到JavaFX系统关闭之后才会调用startAdventure()
方法,这显然不是你想要的。
launch方法javadoc声明:
在应用程序退出之前,启动方法不会返回,无论是通过调用
Platform.exit
还是所有应用程序窗口都已关闭。
您在错误的时间调用startAdventure()
,您应该在应用程序的start()
方法中调用它,而不是在launch()
方法调用之后调用它。
game.startAdventure();
primaryStage.show();
此外,Java启动程序会创建应用程序的实例,因此您无需显式创建。阅读JavaFX application lifecycle以了解此过程。所以你的主要方法应该是:
public static void main(String[] args) {
launch(args);
}
我的一些猜测
此外,您创建新的Adventure()
有点可疑,但如果没有提供进一步的代码,很难确定。冒险可能是一个控制器,所以也许您根本不需要创建一个新的Adventure对象,而是可以从加载器中获取控制器,如下所述:
并且,如果它是一个控制器,那么启动冒险的代码可能发生在控制器的initialize()
方法中,这将由FXMLLoader自动调用。
最终随着应用程序的增长,创建MVC样式的方法可能是有益的,其中Adventure类只是模型数据和逻辑,它被传递到AdventureView,AdventureView是一个控制器,它将模型和FXML视图连接在一起。虽然有关如何实现这一目标的详细技术的讨论超出了本答案的范围,但您可能会从之前链接的传递参数答案中获得一些想法。
其他跟进问题的答案
text和inputText是AdventureGUI.fxml文件中正确初始化的变量,它是使用Scene Builder制作的
如果你使用new
创建冒险类,FXMLLoader将不会初始化Adventure类实例中的变量,而FXMLLoader将创建它自己的Adventure实例并初始化它,这将是独立的来自您创建的实例。由于未针对您的实例初始化文本字段,因此您最终得到NullPointerException。
此外,text和inputText在Adventure类中声明如下:'@ FXML private TextArea text; @FXML private TextArea inputText;'
是的,它们需要由FXMLLoader创建,如果你只是写new Adventure()
就不会发生。
为了解决这一切,我需要在我的控制器类中创建一个initialize()方法?我该怎么做呢?
选项A(让FXMLLoader隐式初始化你的冒险)
将startAdventure()
重命名为initialize()
。
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("AdventureGUI.fxml"));
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.setTitle("Adventure");
primaryStage.show();
}
选项B(明确初始化冒险)
public void start(Stage primaryStage) throws Exception
{
FXMLLoader loader = new FXMLLoader(
getClass().getResource("AdventureGUI.fxml")
);
Parent root = loader.load();
Adventure adventure = loader.<Adventure>getController();
adventure.startAdventure();
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.setTitle("Adventure");
primaryStage.show();
}
示例应用
冒险/ AdventureApp.java
package adventure;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class AdventureApp extends Application {
@Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"AdventureGUI.fxml"
)
);
Parent root = loader.load();
stage.setScene(new Scene(root));
stage.setTitle("Adventure");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
冒险/ Adventure.java
package adventure;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
public class Adventure {
@FXML
private TextArea text;
@FXML
private TextField inputText;
private Player player = new Player();
public void initialize() {
text.setText("Welcome to the land of euphoria!\n");
text.appendText("What's your name?\n");
Platform.runLater(() -> inputText.requestFocus());
inputText.setOnAction(event -> {
player.setName(inputText.getText());
text.appendText("Welcome, " + player.getName() + "\n");
});
player.setLocation("START");
}
}
冒险/ Player.java
package adventure;
public class Player {
private String name;
private String location;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
冒险/ Adventure.java
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="150.0" prefWidth="200.0" spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="adventure.Adventure">
<children>
<TextArea fx:id="text" editable="false" prefHeight="200.0" prefWidth="200.0" wrapText="true" VBox.vgrow="ALWAYS" />
<TextField fx:id="inputText" minHeight="-Infinity" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>