文本 adventure/interactive java 中的小说
text adventure/interactive fiction in java
我决定创建一个帐户,以便提出一个我自己似乎无法弄清楚的问题,或者通过一些谷歌搜索,希望我没有忽略它。
本质上,我正在尝试在 Java 中制作一款文字冒险游戏,但在了解我应该如何将对象概念中的所有内容联系起来时遇到了一些困难。我已经成功地使用 XML stax 并将文件发送到程序,并使用属性等等,使用户可以在其中输入与选项关联的整数,并查看选项是否需要 "item" 或给他们一个物品。然而,我没有对此进行 OOP。
我希望我的新程序能够接受用户输入的字符串,而不仅仅是一个整数,并根据数组列表检查它是否存在。这更接近大多数人可能熟悉的 classic MUD。
我想以模块化的方式设计它,这样我就可以慢慢地添加想法,以及更多的复杂性,所以我也不想要 "well it works so lets leave it alone" 方法。
目前我只是想要接近这个的东西:
一个 Room 对象,它将具有:ID、描述和可交互
一个 Choice 对象(这个我不确定)我考虑过制作一个对象来保存每个房间的可能选择,包括退出和交互
如果是这样,房间对象可能需要一个选择对象。
我已经仔细考虑过,尝试过一些代码,再三考虑过,每次,我都在结束硬编码,而不是我认为应该的,并且制作了比我认为必要的更多的变量,这让我觉得我在思考中遗漏了一些重要的东西。
我还希望这些房间是通过输入的文件创建的,而不是在代码中生成的(所以代码本质上是一个故事 reader/crafter 任何类型,而不是一个)
我也尝试这个太久了,我的解决方案越来越糟糕,但下面是我最近尝试的一个粗略想法:
一个 GameManager class 接受 userInput 并在传递之前对其进行一些检查。我没有传递任何数据,因为我不确定该方法。我也不习惯正则表达式,所以其中一些也可能是错误的,如果是的话,也许会指出来,但这不是我的重点
import java.util.Scanner;
public class GameManager {
private static final String EXIT_PHRASE = "exit";
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
String userStringVal = "";
while(!userStringVal.equals(EXIT_PHRASE)){
userStringVal= userInput.nextLine();
if(checkKeywords(userStringVal)){
System.out.println("matches keyword");
}
else System.out.println("didnt match a keyword");
}
userInput.close();
}
public static boolean checkKeywords(String string){
boolean isKeyword = false;
string.toLowerCase();
if(string.matches("travel.*") || string.matches("search.*")){
System.out.println("passed first check");
String substring = string.substring(6);
if(matchDirection(substring)){
isKeyword = true;
}
}
return isKeyword;
}
public static boolean matchDirection(String string){
boolean hasDirection = false;
if(string.matches(".*\bnorth|south|east|west|northeast|northwest|southeast| southwest|up|down")){
hasDirection = true;
}
return hasDirection;
}
}
我这样想的 Room 对象:
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class Room {
private String roomDescription = "";
private int roomID=0;
private int northExit=0;
private int southExit=0;
private int eastExit=0;
private int westExit=0;
private int northeastExit=0;
private int northwestExit=0;
private int southeastExit=0;
private int southwestExit=0;
private int upExit=0;
private int downExit=0;
private String[] interactables = new String[10];
private Options options = new Options();
public Room(XMLStreamReader reader) throws XMLStreamException{
setAttValues(reader);
setRoomDescription(reader);
setUpOptions();
}
public void setinteractables(XMLStreamReader reader){
int count = reader.getAttributeCount();
for(int i = 0; i < count; i++){
interactables[i] = reader.getAttributeValue(i);
}
}
public void setAttValues(XMLStreamReader reader){
int count = reader.getAttributeCount();
for(int i = 0; i < count; i++){
String att = reader.getAttributeLocalName(i);
if(att !=""){
switch(att){
case "North": northExit=Integer.parseInt(att);
case "South": southExit=Integer.parseInt(att);
case "East": eastExit=Integer.parseInt(att);
case "West": westExit=Integer.parseInt(att);
case "NorthEast": northeastExit=Integer.parseInt(att);
case "NorthWest": northwestExit=Integer.parseInt(att);
case "SouthEast": southeastExit=Integer.parseInt(att);
case "SouthWest": southwestExit=Integer.parseInt(att);
case "Up": upExit=Integer.parseInt(att);
case "Down": downExit=Integer.parseInt(att);
case "ID": roomID=Integer.parseInt(att);
}
}
}
}
public void setRoomDescription(XMLStreamReader reader) throws XMLStreamException{
roomDescription = reader.getElementText();
}
public void setUpOptions(){
options.setCardinalPointers(northExit, southExit, eastExit, westExit);
options.setIntercardinalPointers(northeastExit, northwestExit, southeastExit, southwestExit);
options.setElevationPointers(upExit, downExit);
}
}
我该怎么做才能确保我不必用这么多变量来说明这么多方向?
这是我考虑过的一个选项 class 的快速粗略想法,但我没有完成决定我已经在错误的方向上走得太远了
public class Options {
private int northPointer = 0;
private int southPointer= 0;
private int eastPointer = 0;
private int westPointer = 0;
private int northeastPointer= 0;
private int northwestPointer = 0;
private int southeastPointer = 0;
private int southwestPointer = 0;
private int upPointer = 0;
private int downPointer = 0;
private String northInteractable = "";
private String southInteractable = "";
private String eastInteractable = "";
private String westInteractable = "";
private String northeastInteractable ="";
private String northwestInteractable = "";
private String southeastInteractable = "";
private String southwestInteractable = "";
private String upInteractable = "";
private String downInteractable = "";
public Options(){
}
public void setCardinalPointers(int north, int south, int east, int west){
northPointer = north;
southPointer = south;
eastPointer = east;
westPointer = west;
}
public void setIntercardinalPointers(int northeast, int northwest, int southeast, int southwest){
northeastPointer = northeast;
northwestPointer=northwest;
southeastPointer=southeast;
southwestPointer=southwest;
}
public void setElevationPointers(int up, int down){
upPointer = up;
downPointer = down;
}
public String whatToReturn(String string){
String importantPart = "";
if(string.matches("travel.*")){
String substring = string.substring(6);
}
else {
importantPart = "Interactable";
String substring = string.substring(6);
if (substring.matches("\bnorth\b")) {
if(northInteractable!=0){
}
}
else if (substring.matches("\bsouth\b"))
else if (substring.matches("\beast\b"))
else if (substring.matches("\bwest\b"))
else if (substring.contains("northeast"))
else if (substring.contains("northwest"))
else if (substring.contains("southeast"))
else if (substring.contains("southwest"))
else if (substring.contains("up"))
else if (substring.contains("down"))
}
return importantPart;
}
}
直到我输入这个之后我才看到冒险标签,所以我会从那里开始仔细阅读,但仍然会 post 这个,所以如果有一个好的答案我很抱歉并且我已经还没找到。
回顾一下:将一些对象关联起来以创建一个房间对象(从文件中获取其信息(XML 是我过去使用的信息))的好方法是什么?有出口,描述, 和互动。并且用户与这些基于可以自由输入的关键字进行交互,并且不限于数组的持有关键字的索引值。
我在想,当用户键入 "travel north" 之类的内容时,首先检查他们是否键入了关键字,在本例中是旅行,然后是方向。然后用其他方式检查它是否表示旅行,用一个可能的 northExit 向北检查一个房间可能有也可能没有。然后如果它是另一个关键字,比如检查,为了方便也有完全相同的方向,但检查不同的字符串。
然后,如果房间 "northExit" 存在,则以某种方式获得一个选项,其中包含指向另一个房间 ID 的指针。尽管在考虑未来需要物品才能到达下一个房间的可能性时,这种思考过程让我产生了问题。此外,store/acquire 这些选项在哪里造成了一些困难。
有两件事我想跟大家介绍一下。第一个,在enum
。您可以将其视为一种特殊的 class,其中所有可能的选项都是 enum 在 class 定义中指定的。这非常适合诸如方向之类的事情。枚举可以很简单,您只需列出所有可能用于其他 classes:
的选项
public enum Direction {
NORTH, NORTH_EAST, EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NOTH_WEST;
}
如果您希望它们具有自己的方法和属性,它们可能会更复杂一些:
public enum Direction {
NORTH(true), NORTH_EAST(false), EAST(true), SOUTH_EAST(false), SOUTH(true), SOUTH_WEST(false), WEST(true), NOTH_WEST(false);
private final boolean isCardinal;
private Direction(boolean isCardinal){
this.isCardinal = isCardinal;
}
public boolean isCardinal(){
return isCardinal;
}
public static Collection<Direction> getCardinalDirections(){
return Arrays.asList(Direction.values()).stream().filter(Direction::isCardinal).collect(Collectors.toList());
}
public static Collection<Direction> getIncardinalDirections(){
return Arrays.asList(Direction.values()).stream().filter(x -> !x.isCardinal()).collect(Collectors.toList());
}
}
请详细阅读 Java enum
类型 here。
我要向大家介绍的第二件事是被称为Map
的数据结构。地图也称为字典,这通常有助于理解它们的工作原理。地图会将一个对象映射到另一个对象,就像字典如何将一个词映射到它的定义,或者一本phone书将一个人的名字映射到他们的phone 号。我们可以通过使用 Map
将您的 Room
class 简化一吨。我不会复制您的所有代码,因为我关注的是您的 Room
现在存在:
public class Room {
private Map<Direction, Room> exits;
public Room(){
this.exits = new HashMap<>();
}
public void setExit(Direction direction, Room room){
this.exits.put(direction, room);
}
public Room getExit(Direction direction){
return this.exits.get(direction);
}
}
请详细了解 Java Map
界面 here。
当然,您需要调整从 XML 等读取的方法。但是,现在,您的 Room
class 应该大大简化。
我希望这能为您指明一个有用的方向。
我决定创建一个帐户,以便提出一个我自己似乎无法弄清楚的问题,或者通过一些谷歌搜索,希望我没有忽略它。
本质上,我正在尝试在 Java 中制作一款文字冒险游戏,但在了解我应该如何将对象概念中的所有内容联系起来时遇到了一些困难。我已经成功地使用 XML stax 并将文件发送到程序,并使用属性等等,使用户可以在其中输入与选项关联的整数,并查看选项是否需要 "item" 或给他们一个物品。然而,我没有对此进行 OOP。
我希望我的新程序能够接受用户输入的字符串,而不仅仅是一个整数,并根据数组列表检查它是否存在。这更接近大多数人可能熟悉的 classic MUD。
我想以模块化的方式设计它,这样我就可以慢慢地添加想法,以及更多的复杂性,所以我也不想要 "well it works so lets leave it alone" 方法。
目前我只是想要接近这个的东西:
一个 Room 对象,它将具有:ID、描述和可交互 一个 Choice 对象(这个我不确定)我考虑过制作一个对象来保存每个房间的可能选择,包括退出和交互
如果是这样,房间对象可能需要一个选择对象。
我已经仔细考虑过,尝试过一些代码,再三考虑过,每次,我都在结束硬编码,而不是我认为应该的,并且制作了比我认为必要的更多的变量,这让我觉得我在思考中遗漏了一些重要的东西。
我还希望这些房间是通过输入的文件创建的,而不是在代码中生成的(所以代码本质上是一个故事 reader/crafter 任何类型,而不是一个)
我也尝试这个太久了,我的解决方案越来越糟糕,但下面是我最近尝试的一个粗略想法:
一个 GameManager class 接受 userInput 并在传递之前对其进行一些检查。我没有传递任何数据,因为我不确定该方法。我也不习惯正则表达式,所以其中一些也可能是错误的,如果是的话,也许会指出来,但这不是我的重点
import java.util.Scanner;
public class GameManager {
private static final String EXIT_PHRASE = "exit";
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
String userStringVal = "";
while(!userStringVal.equals(EXIT_PHRASE)){
userStringVal= userInput.nextLine();
if(checkKeywords(userStringVal)){
System.out.println("matches keyword");
}
else System.out.println("didnt match a keyword");
}
userInput.close();
}
public static boolean checkKeywords(String string){
boolean isKeyword = false;
string.toLowerCase();
if(string.matches("travel.*") || string.matches("search.*")){
System.out.println("passed first check");
String substring = string.substring(6);
if(matchDirection(substring)){
isKeyword = true;
}
}
return isKeyword;
}
public static boolean matchDirection(String string){
boolean hasDirection = false;
if(string.matches(".*\bnorth|south|east|west|northeast|northwest|southeast| southwest|up|down")){
hasDirection = true;
}
return hasDirection;
}
}
我这样想的 Room 对象:
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class Room {
private String roomDescription = "";
private int roomID=0;
private int northExit=0;
private int southExit=0;
private int eastExit=0;
private int westExit=0;
private int northeastExit=0;
private int northwestExit=0;
private int southeastExit=0;
private int southwestExit=0;
private int upExit=0;
private int downExit=0;
private String[] interactables = new String[10];
private Options options = new Options();
public Room(XMLStreamReader reader) throws XMLStreamException{
setAttValues(reader);
setRoomDescription(reader);
setUpOptions();
}
public void setinteractables(XMLStreamReader reader){
int count = reader.getAttributeCount();
for(int i = 0; i < count; i++){
interactables[i] = reader.getAttributeValue(i);
}
}
public void setAttValues(XMLStreamReader reader){
int count = reader.getAttributeCount();
for(int i = 0; i < count; i++){
String att = reader.getAttributeLocalName(i);
if(att !=""){
switch(att){
case "North": northExit=Integer.parseInt(att);
case "South": southExit=Integer.parseInt(att);
case "East": eastExit=Integer.parseInt(att);
case "West": westExit=Integer.parseInt(att);
case "NorthEast": northeastExit=Integer.parseInt(att);
case "NorthWest": northwestExit=Integer.parseInt(att);
case "SouthEast": southeastExit=Integer.parseInt(att);
case "SouthWest": southwestExit=Integer.parseInt(att);
case "Up": upExit=Integer.parseInt(att);
case "Down": downExit=Integer.parseInt(att);
case "ID": roomID=Integer.parseInt(att);
}
}
}
}
public void setRoomDescription(XMLStreamReader reader) throws XMLStreamException{
roomDescription = reader.getElementText();
}
public void setUpOptions(){
options.setCardinalPointers(northExit, southExit, eastExit, westExit);
options.setIntercardinalPointers(northeastExit, northwestExit, southeastExit, southwestExit);
options.setElevationPointers(upExit, downExit);
}
}
我该怎么做才能确保我不必用这么多变量来说明这么多方向?
这是我考虑过的一个选项 class 的快速粗略想法,但我没有完成决定我已经在错误的方向上走得太远了
public class Options {
private int northPointer = 0;
private int southPointer= 0;
private int eastPointer = 0;
private int westPointer = 0;
private int northeastPointer= 0;
private int northwestPointer = 0;
private int southeastPointer = 0;
private int southwestPointer = 0;
private int upPointer = 0;
private int downPointer = 0;
private String northInteractable = "";
private String southInteractable = "";
private String eastInteractable = "";
private String westInteractable = "";
private String northeastInteractable ="";
private String northwestInteractable = "";
private String southeastInteractable = "";
private String southwestInteractable = "";
private String upInteractable = "";
private String downInteractable = "";
public Options(){
}
public void setCardinalPointers(int north, int south, int east, int west){
northPointer = north;
southPointer = south;
eastPointer = east;
westPointer = west;
}
public void setIntercardinalPointers(int northeast, int northwest, int southeast, int southwest){
northeastPointer = northeast;
northwestPointer=northwest;
southeastPointer=southeast;
southwestPointer=southwest;
}
public void setElevationPointers(int up, int down){
upPointer = up;
downPointer = down;
}
public String whatToReturn(String string){
String importantPart = "";
if(string.matches("travel.*")){
String substring = string.substring(6);
}
else {
importantPart = "Interactable";
String substring = string.substring(6);
if (substring.matches("\bnorth\b")) {
if(northInteractable!=0){
}
}
else if (substring.matches("\bsouth\b"))
else if (substring.matches("\beast\b"))
else if (substring.matches("\bwest\b"))
else if (substring.contains("northeast"))
else if (substring.contains("northwest"))
else if (substring.contains("southeast"))
else if (substring.contains("southwest"))
else if (substring.contains("up"))
else if (substring.contains("down"))
}
return importantPart;
}
}
直到我输入这个之后我才看到冒险标签,所以我会从那里开始仔细阅读,但仍然会 post 这个,所以如果有一个好的答案我很抱歉并且我已经还没找到。
回顾一下:将一些对象关联起来以创建一个房间对象(从文件中获取其信息(XML 是我过去使用的信息))的好方法是什么?有出口,描述, 和互动。并且用户与这些基于可以自由输入的关键字进行交互,并且不限于数组的持有关键字的索引值。
我在想,当用户键入 "travel north" 之类的内容时,首先检查他们是否键入了关键字,在本例中是旅行,然后是方向。然后用其他方式检查它是否表示旅行,用一个可能的 northExit 向北检查一个房间可能有也可能没有。然后如果它是另一个关键字,比如检查,为了方便也有完全相同的方向,但检查不同的字符串。
然后,如果房间 "northExit" 存在,则以某种方式获得一个选项,其中包含指向另一个房间 ID 的指针。尽管在考虑未来需要物品才能到达下一个房间的可能性时,这种思考过程让我产生了问题。此外,store/acquire 这些选项在哪里造成了一些困难。
有两件事我想跟大家介绍一下。第一个,在enum
。您可以将其视为一种特殊的 class,其中所有可能的选项都是 enum 在 class 定义中指定的。这非常适合诸如方向之类的事情。枚举可以很简单,您只需列出所有可能用于其他 classes:
public enum Direction {
NORTH, NORTH_EAST, EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NOTH_WEST;
}
如果您希望它们具有自己的方法和属性,它们可能会更复杂一些:
public enum Direction {
NORTH(true), NORTH_EAST(false), EAST(true), SOUTH_EAST(false), SOUTH(true), SOUTH_WEST(false), WEST(true), NOTH_WEST(false);
private final boolean isCardinal;
private Direction(boolean isCardinal){
this.isCardinal = isCardinal;
}
public boolean isCardinal(){
return isCardinal;
}
public static Collection<Direction> getCardinalDirections(){
return Arrays.asList(Direction.values()).stream().filter(Direction::isCardinal).collect(Collectors.toList());
}
public static Collection<Direction> getIncardinalDirections(){
return Arrays.asList(Direction.values()).stream().filter(x -> !x.isCardinal()).collect(Collectors.toList());
}
}
请详细阅读 Java enum
类型 here。
我要向大家介绍的第二件事是被称为Map
的数据结构。地图也称为字典,这通常有助于理解它们的工作原理。地图会将一个对象映射到另一个对象,就像字典如何将一个词映射到它的定义,或者一本phone书将一个人的名字映射到他们的phone 号。我们可以通过使用 Map
将您的 Room
class 简化一吨。我不会复制您的所有代码,因为我关注的是您的 Room
现在存在:
public class Room {
private Map<Direction, Room> exits;
public Room(){
this.exits = new HashMap<>();
}
public void setExit(Direction direction, Room room){
this.exits.put(direction, room);
}
public Room getExit(Direction direction){
return this.exits.get(direction);
}
}
请详细了解 Java Map
界面 here。
当然,您需要调整从 XML 等读取的方法。但是,现在,您的 Room
class 应该大大简化。
我希望这能为您指明一个有用的方向。