将 Swing 集成到一个简单的文字冒险游戏中
我对 Java 中的一些中间概念相当陌生.最近我制作了一款名为 DazzleQuest 的文字冒险游戏,它完全在开发者控制台/终端中运行.它涉及到我的朋友作为角色,所以我想向他们展示它并通过将命令行的功能和控制台的输出转移到由 JTextArea
组成的简单 Swing 界面来获得 Java 经验以显示游戏的输出和一个带有 ActionListener
的 JTextField
,用于处理来自用户的命令.
I am fairly new to some intermediate concepts in Java. Recently I made a text adventure game called DazzleQuest that runs entirely in the developer console/terminal. It involves my friends as characters so I wanted to show it to them and gain experience with Java by transferring the functionality of the command line and output from the console to a simple Swing interface comprised of a JTextArea
to show the game's output and a JTextField
, with ActionListener
, to handle commands from the user.
我的主 DazzleQuest
类包含名为 run()
和 handleCommand()
的方法,我认为我需要将它们与我的 Frame
类及其子类 TextFieldHandler
[扩展了 ActionListener
].我想知道,总的来说,集成这些方法和类的最佳方式是什么. 我目前的尝试一直令人困惑,虽然我对如何使不同的类和方法进行通信有了基本的了解,但它是暂定的.
My main DazzleQuest
class contains methods called run()
and handleCommand()
, which I figure I need to integrate with my Frame
class and its subclass TextFieldHandler
[which extends ActionListener
]. I am wondering, in general, what is the best way to integrate these methods and classes. My current attempts have been confusing and though I have a basic grasp on how to make different classes and methods communicate, it is tentative.
对于冗长和缺乏特异性表示歉意.我会分享我的代码,但不确定要提供多少以及具体提供什么.如果你认为你可以回答我的问题,但需要一个我所拥有的例子,请这样说.甚至将伪代码作为答案也将不胜感激.谢谢!了解这一点可能对我作为程序员的教育非常有帮助.
Apologies for the wordiness and lack of specificity. I would share my code but am unsure of how much and exactly what to give. If you think you can answer my question but need an example of what I have, please say so. Even pseudocode as an answer would be appreciated. Thank you! Understanding this could be very helpful for my education as a programmer.
以下是我的代码的简化示例,这些代码来自完全在开发者控制台中运行的游戏版本.这是我的主课DazzleQuest
:
Here are simplified examples of my code from the version of the game that runs entirely in the developer console. This is my main 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
类中:
And here is my current JFrame
setup, in the 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 + "
");
field.setText("");
}
}
public static void main(String args[]) {
Frame test = new Frame();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
我知道如何将输出打印到 JTextArea
而不是控制台.我的问题是如何让 handleCommand()
与 Frame
类中的 actionPerformed()
一起工作,或者我是否应该设置一个动作主类中的听众或类似的东西.任何实施示例将不胜感激.
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, or whether I should set up an action listener in the main class or something like that. Any examples of implementation would be greatly appreciated.
再次感谢您告诉我的任何事情!
Thanks again for anything you can tell me!
推荐答案
首先,关于包含代码,你应该看看https:///stackoverflow.com/help/mcve 了解如何帮助我们帮助您.
First, regarding including code, you should take a look at https://stackoverflow.com/help/mcve for how to help us help you.
现在,鉴于您还没有提供任何代码(还没有!)就应该如何构建程序提出建议有点棘手.但无论如何我都会尝试,并且可能会在您提供 MWE 后编辑答案.
Now, given that you haven't provided any code (yet!) giving suggestions on how you should structure your program is a bit tricky. But I'll make an attempt anyways and might edit the answer when you've provided a MWE.
在您的情况下,JTextArea
实际上只是一个花哨的 System.out.print
,因为您只会使用它来显示冒险游戏输出的文本(如果我'我理解你正确).所以基本上,您可以编写一个接受字符串的方法,并且该方法会将该字符串附加到您的 JTextArea
中.然后用这个方法替换你当前的输出行.
In your case, JTextArea
is really just a fancy System.out.print
as you will only use it to display the text that your adventure game outputs (if I'm understanding you correctly). So basically, you can write a method that accepts a string, and that method will append that string to your JTextArea
. Then just replace your current output-lines with this method.
然后你有你的 JTextField
你想要替换你的(我猜) Scanner(System.in)
.我假设您知道如何设置响应 Enter
或 submit
按钮的动作侦听器.如何设置这些并不奇怪,很多指南都在讨论如何设置.https://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html 给出了一个很好的例子.
Then you have your JTextField
which you want to replace your (I'm guessing) Scanner(System.in)
with. I assume you know how to set up an action listener that responds to Enter
or a submit
-button.
How to set these up is not all that strange, and lots of guides talk about how to do it. https://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html gives a good example.
现在,一般来说关于您的程序的结构.您确实不希望依赖于用户输入文本或显示文本的方式.我的意思是您不希望输入或显示逻辑干扰您的游戏(业务)逻辑.您的游戏逻辑应该只接收来自任何地方的输入,并将其输出到任何地方.然后调用函数决定如何处理信息以及如何处理这些信息不是游戏逻辑关心的问题.
Now, in general regarding the structure of your program. You do not want to be dependent on how the user enters the text or how you display it. What I mean with this is that you do not want input- or display-logic to meddle with your game (business) logic. Your game logic should just receive input, from where ever, and output it to where ever. How and what the calling functions then decide to do with the information is not for the game logic to care about.
因此,应用于您发布的方法名称.我假设 run()
是你开始的地方.由于您有始终想要显示的输出,因此您可能希望在此处传递一个 interface
具有 print(string)
(或类似)方法的一种将文本打印到用于显示文本的任何文本元素的方法,无论是 System.out
还是 JTextArea
.run()
方法永远不需要知道.handleCommand()
也应该只接受一个值(我假设是一个字符串)并按应有的方式处理它,无论是谁或什么调用它.
So, applied to the method names you posted. I assume run()
is where you kick things off. As you have output that you always want to display, you might want to pass in an interface
here that has the method print(string)
(or the like) which should be a method that prints the text to whatever text-element is used to display the text, be it System.out
or JTextArea
. The run()
method never needs to know.
handleCommand()
should also just accept a value (I assume a String) and handle it like it should, no matter who or what called it.
我无法在没有代码的情况下为您提供更多建议.但我的一般建议是:不要将表示逻辑与业务逻辑混为一谈.并尽可能少地给每个方法提供信息,因为给它们提供比实际需要更多的信息通常会导致流程和结构不够灵活.
I'm having trouble giving you more advice with no code. But my general recommendation is: Don't mix presentation logic with business logic. And give each method as little info as possible, because giving them more than they actually need usually leads to a less flexible flow and structure.
现在编辑,添加了一些代码.
EDIT now that some code has been added.
我知道如何将输出打印到 JTextArea 而不是控制台.我的问题是如何让 handleCommand() 与 Frame 类中的 actionPerformed() 一起工作
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 提供了一些关于如何编写监听器的好信息.不过我也会给你一些建议代码.
Go with the actionPerformed()
approach. I recommend this because you won't have to bother with as much if you decide to Thread
your application sometime in the future (multiplayer?). https://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html gives some good info about how to write your listener. But I'll give you some suggestion code as well.
...
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
类(在您的情况下为 Frame
)的一种方法,它只是附加发送给它的任何字符串到它的绘图区域,无论是 System.out
还是 JTextArea
.
So now you have a very small run()
method that has no real tie-in to either the logic or the display. ui.print(str)
is a method that your UI
class (Frame
in your case) that just appends what ever string is sent to it to it's drawing area, be it System.out
or a JTextArea
.
commandHandler
是新的.这是你的游戏逻辑应该在的地方.它有一个方法 handle(string)
,它是你的旧 handleCommand(string)
.它有一个返回布尔值的 continue()
方法.每当您希望故事继续时,例如当用户输入命令时,布尔值都应设置为 true.最后是 events()
(这是一个坏名字),它返回自最后一个命令发送以来发生的事情,并为用户提供下一步操作的选项.我还没有实现它,因为我只是想给你这个概念.UI 不做任何逻辑处理.run()
方法不期望任何东西,它只是不断检查 continue()
是否为真.commandHandler
是所有业务的所在.
commandHandler
is new. This is where your game logic should be. It has a method handle(string)
which is your old handleCommand(string)
. It has a continue()
method that returns a boolean. The boolean should be set to true whenever you want the story to continue, eg when the user enters a command. And finally events()
(which is a bad name) that returns what has happened since the last command was sent in and gives the users options on what to do next. I've not done an implementation of that, as I just want to give the concept to you. The UI doesn't do any logic processing. The run()
method doesn't expect anything, it just keeps checking if continue()
is true. commandHandler
is where all the bizz is.
现在,您确实有一个无限循环正在运行.因此,如果您遇到任何性能问题,您可以查看 Thread
.这个模型应该支持迁移到它.
Now, you do have a infinite loop running. So if you get any performance issues you could look into Thread
. This model should support a move to it.
相关文章