将 Swing 集成到一个简单的文字冒险游戏中
Integrating Swing in a simple text adventure game
我对 Java 中的一些中级概念还很陌生。最近我制作了一款名为 DazzleQuest 的文字冒险游戏,它完全在开发者 console/terminal 中运行。它涉及我的朋友作为角色,所以我想向他们展示它并通过将命令行的功能和控制台的输出转移到一个简单的 Swing 界面来获得 Java 的经验,该界面由 JTextArea
组成显示游戏的输出和一个 JTextField
和 ActionListener
来处理来自用户的命令。
我的主要 DazzleQuest
class 包含名为 run()
和 handleCommand()
的方法,我认为我需要将它们与我的 Frame
[=47= 集成] 及其子 class TextFieldHandler
[扩展 ActionListener
]。 我想知道,一般来说,整合这些方法和 classes 的最佳方法是什么。我目前的尝试一直很混乱,尽管我对如何让不同的classes和methods进行通信,暂定。
对于冗长和缺乏具体性,我们深表歉意。我会分享我的代码,但不确定要提供多少以及具体提供什么。如果您认为您可以回答我的问题但需要我所拥有的示例,请这样说。即使是伪代码作为答案也会受到赞赏。谢谢!理解这一点对我作为程序员的教育很有帮助。
编辑:这里是我的代码的简化示例,来自完全在开发者控制台中运行的游戏版本。这是我的主要 class DazzleQuest
:
public class DazzleQuest {
public void run() {
listCommands();
for (;;) {
StdOut.println(new StringBuilder("You are in ").append(currentRoom.getName()).append(".").toString());
StdOut.println(new StringBuilder("You can go to: ").append(currentRoom.listExits()).toString());
StdOut.print("> ");
handleCommand(StdIn.readLine());
StdOut.println();
}
public void handleCommand(String line) {
String[] words = line.split(" ");
if (words[0].equals("look"))
look();
}
}
}
这是我当前的 JFrame
设置,在 Frame
class:
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JTextArea;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Frame extends JFrame {
public static JTextField field;
public JTextArea area;
public Frame() {
setLayout(new FlowLayout());
area = new JTextArea(20, 40);
area.setEditable(false);
field = new JTextField(20);
add(area);
add(field);
pack();
setVisible(true);
TextFieldHandler handler = new TextFieldHandler();
field.addActionListener(handler);
}
public class TextFieldHandler implements ActionListener{
public void actionPerformed(ActionEvent event)
{
String line = field.getText();
area.append(line + "\n");
field.setText("");
}
}
public static void main(String args[]) {
Frame test = new Frame();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
我知道如何将输出打印到 JTextArea
而不是控制台。我的问题是如何让 handleCommand()
与 Frame
class 中的 actionPerformed()
一起工作,或者我是否应该在主 class 中设置一个动作侦听器或类似的东西。任何实施示例将不胜感激。
再次感谢您告诉我的一切!
首先,关于包含代码,您应该查看 https://whosebug.com/help/mcve 了解如何帮助我们帮助您。
现在,鉴于您还没有提供任何代码(还!),就您应该如何构建程序提出建议有点棘手。但无论如何我都会尝试,并可能会在您提供 MWE 后编辑答案。
在您的情况下,JTextArea
实际上只是一个花哨的 System.out.print
,因为您只会用它来显示您的冒险游戏输出的文本(如果我没理解错的话)。所以基本上,您可以编写一个接受字符串的方法,该方法会将那个字符串附加到您的 JTextArea
。然后用这个方法替换你当前的输出行。
然后你有了 JTextField
,你想用它替换你的(我猜)Scanner(System.in)
。我假设您知道如何设置响应 Enter
或 submit
按钮的动作侦听器。
如何设置这些并不奇怪,很多指南都在谈论如何设置。 https://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html 举了一个很好的例子。
现在,大致介绍一下您的程序结构。
您不 想要依赖于如何 用户输入文本或您如何显示文本。我的意思是您不希望输入或显示逻辑干扰您的游戏 (business) 逻辑。您的游戏逻辑应该只接收来自任何地方的输入,并将其输出到任何地方。调用函数随后决定如何以及如何处理这些信息不是游戏逻辑所关心的。
因此,应用于您发布的方法名称。我假设 run()
是您开始的地方。由于您有总是想要显示的输出,因此您可能希望在此处传递具有方法 print(string)
(或类似方法)的 interface
,该方法应该是将文本打印到任何文本的方法- 元素用于显示文本,可以是 System.out
或 JTextArea
。 run()
方法永远不需要知道。
handleCommand()
也应该只接受一个值(我假设是一个字符串)并按应有的方式处理它,无论是谁或什么调用它。
我无法在没有代码的情况下为您提供更多建议。但我的一般建议是:不要将表示逻辑与业务逻辑混合。并尽可能少地为每个方法提供信息,因为给它们提供的信息超过它们实际需要的信息通常会导致流程和结构的灵活性降低。
编辑,现在添加了一些代码。
I know how to print output to the JTextArea instead of to the console. My issue is how exactly to get handleCommand() to work with actionPerformed() in the Frame class
采用 actionPerformed()
方法。我推荐这个,因为如果您决定在将来某个时候 Thread
您的应用程序(多人游戏?),您就不必费心了。 https://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html 提供了一些关于如何编写监听器的有用信息。但我也会给你一些建议代码。
...
area.setEditable(false);
field = new JTextField(20);
field.addActionListener(new SendText());
....
class SendText implements ActionListener{
public void actionPerformed(ActionEvent ae){
if(ae.getSource() == field){
String str = field.getText();
if(!str.equals("")){
commandHandler.handle(str);
}
}
}
}
然后重写你的run()
方法
public void run(){
ui.print(commandHandler.listCommands());
while(true){
if(commandHandler.continue()){
ui.print(commandHandler.events());
}
}
}
现在您有了一个非常小的 run()
方法,它与逻辑或显示都没有真正的关联。 ui.print(str)
是一种方法,您的 UI
class(Frame
在您的情况下)只是将发送给它的任何字符串附加到它的绘图区域,无论是 System.out
或 JTextArea
.
commandHandler
是新的。这就是您的游戏逻辑所在的位置。它有一个方法 handle(string)
,这是您的旧方法 handleCommand(string)
。它有一个 continue()
方法,returns 一个布尔值。每当您希望故事继续时,布尔值都应设置为 true,例如,当用户输入命令时。最后 events()
(这是个坏名字)returns 自上次命令发送以来发生的事情,并为用户提供下一步操作的选项。我还没有实现它,因为我只是想把这个概念给你。 UI 不做任何逻辑处理。 run()
方法不期望任何东西,它只是不断检查 continue()
是否为真。 commandHandler
是最热闹的地方。
现在,您确实有一个无限循环 运行。因此,如果您遇到任何性能问题,可以查看 Thread
。该模型应该支持迁移到它。
我对 Java 中的一些中级概念还很陌生。最近我制作了一款名为 DazzleQuest 的文字冒险游戏,它完全在开发者 console/terminal 中运行。它涉及我的朋友作为角色,所以我想向他们展示它并通过将命令行的功能和控制台的输出转移到一个简单的 Swing 界面来获得 Java 的经验,该界面由 JTextArea
组成显示游戏的输出和一个 JTextField
和 ActionListener
来处理来自用户的命令。
我的主要 DazzleQuest
class 包含名为 run()
和 handleCommand()
的方法,我认为我需要将它们与我的 Frame
[=47= 集成] 及其子 class TextFieldHandler
[扩展 ActionListener
]。 我想知道,一般来说,整合这些方法和 classes 的最佳方法是什么。我目前的尝试一直很混乱,尽管我对如何让不同的classes和methods进行通信,暂定。
对于冗长和缺乏具体性,我们深表歉意。我会分享我的代码,但不确定要提供多少以及具体提供什么。如果您认为您可以回答我的问题但需要我所拥有的示例,请这样说。即使是伪代码作为答案也会受到赞赏。谢谢!理解这一点对我作为程序员的教育很有帮助。
编辑:这里是我的代码的简化示例,来自完全在开发者控制台中运行的游戏版本。这是我的主要 class DazzleQuest
:
public class DazzleQuest {
public void run() {
listCommands();
for (;;) {
StdOut.println(new StringBuilder("You are in ").append(currentRoom.getName()).append(".").toString());
StdOut.println(new StringBuilder("You can go to: ").append(currentRoom.listExits()).toString());
StdOut.print("> ");
handleCommand(StdIn.readLine());
StdOut.println();
}
public void handleCommand(String line) {
String[] words = line.split(" ");
if (words[0].equals("look"))
look();
}
}
}
这是我当前的 JFrame
设置,在 Frame
class:
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JTextArea;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Frame extends JFrame {
public static JTextField field;
public JTextArea area;
public Frame() {
setLayout(new FlowLayout());
area = new JTextArea(20, 40);
area.setEditable(false);
field = new JTextField(20);
add(area);
add(field);
pack();
setVisible(true);
TextFieldHandler handler = new TextFieldHandler();
field.addActionListener(handler);
}
public class TextFieldHandler implements ActionListener{
public void actionPerformed(ActionEvent event)
{
String line = field.getText();
area.append(line + "\n");
field.setText("");
}
}
public static void main(String args[]) {
Frame test = new Frame();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
我知道如何将输出打印到 JTextArea
而不是控制台。我的问题是如何让 handleCommand()
与 Frame
class 中的 actionPerformed()
一起工作,或者我是否应该在主 class 中设置一个动作侦听器或类似的东西。任何实施示例将不胜感激。
再次感谢您告诉我的一切!
首先,关于包含代码,您应该查看 https://whosebug.com/help/mcve 了解如何帮助我们帮助您。
现在,鉴于您还没有提供任何代码(还!),就您应该如何构建程序提出建议有点棘手。但无论如何我都会尝试,并可能会在您提供 MWE 后编辑答案。
在您的情况下,JTextArea
实际上只是一个花哨的 System.out.print
,因为您只会用它来显示您的冒险游戏输出的文本(如果我没理解错的话)。所以基本上,您可以编写一个接受字符串的方法,该方法会将那个字符串附加到您的 JTextArea
。然后用这个方法替换你当前的输出行。
然后你有了 JTextField
,你想用它替换你的(我猜)Scanner(System.in)
。我假设您知道如何设置响应 Enter
或 submit
按钮的动作侦听器。
如何设置这些并不奇怪,很多指南都在谈论如何设置。 https://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html 举了一个很好的例子。
现在,大致介绍一下您的程序结构。 您不 想要依赖于如何 用户输入文本或您如何显示文本。我的意思是您不希望输入或显示逻辑干扰您的游戏 (business) 逻辑。您的游戏逻辑应该只接收来自任何地方的输入,并将其输出到任何地方。调用函数随后决定如何以及如何处理这些信息不是游戏逻辑所关心的。
因此,应用于您发布的方法名称。我假设 run()
是您开始的地方。由于您有总是想要显示的输出,因此您可能希望在此处传递具有方法 print(string)
(或类似方法)的 interface
,该方法应该是将文本打印到任何文本的方法- 元素用于显示文本,可以是 System.out
或 JTextArea
。 run()
方法永远不需要知道。
handleCommand()
也应该只接受一个值(我假设是一个字符串)并按应有的方式处理它,无论是谁或什么调用它。
我无法在没有代码的情况下为您提供更多建议。但我的一般建议是:不要将表示逻辑与业务逻辑混合。并尽可能少地为每个方法提供信息,因为给它们提供的信息超过它们实际需要的信息通常会导致流程和结构的灵活性降低。
编辑,现在添加了一些代码。
I know how to print output to the JTextArea instead of to the console. My issue is how exactly to get handleCommand() to work with actionPerformed() in the Frame class
采用 actionPerformed()
方法。我推荐这个,因为如果您决定在将来某个时候 Thread
您的应用程序(多人游戏?),您就不必费心了。 https://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html 提供了一些关于如何编写监听器的有用信息。但我也会给你一些建议代码。
...
area.setEditable(false);
field = new JTextField(20);
field.addActionListener(new SendText());
....
class SendText implements ActionListener{
public void actionPerformed(ActionEvent ae){
if(ae.getSource() == field){
String str = field.getText();
if(!str.equals("")){
commandHandler.handle(str);
}
}
}
}
然后重写你的run()
方法
public void run(){
ui.print(commandHandler.listCommands());
while(true){
if(commandHandler.continue()){
ui.print(commandHandler.events());
}
}
}
现在您有了一个非常小的 run()
方法,它与逻辑或显示都没有真正的关联。 ui.print(str)
是一种方法,您的 UI
class(Frame
在您的情况下)只是将发送给它的任何字符串附加到它的绘图区域,无论是 System.out
或 JTextArea
.
commandHandler
是新的。这就是您的游戏逻辑所在的位置。它有一个方法 handle(string)
,这是您的旧方法 handleCommand(string)
。它有一个 continue()
方法,returns 一个布尔值。每当您希望故事继续时,布尔值都应设置为 true,例如,当用户输入命令时。最后 events()
(这是个坏名字)returns 自上次命令发送以来发生的事情,并为用户提供下一步操作的选项。我还没有实现它,因为我只是想把这个概念给你。 UI 不做任何逻辑处理。 run()
方法不期望任何东西,它只是不断检查 continue()
是否为真。 commandHandler
是最热闹的地方。
现在,您确实有一个无限循环 运行。因此,如果您遇到任何性能问题,可以查看 Thread
。该模型应该支持迁移到它。