我正在玩棋盘游戏。在每个回合中,玩家可以使用一张牌(支付一些代币),例如,允许他们绘制另一张牌,允许他们将他的棋子放在棋盘上而忽略一些规则(仅转一圈),允许他们重新掷骰子等等。我被要求从JSON文件加载这些卡,以便可以在不重新编译/更新整个软件的情况下为游戏添加新卡,还因为“硬编码它们会很糟糕”。
这些卡片有名称和成本,序列化非常简单。但是当谈到序列化他们的行为及其影响时,我就迷失了。我想我可以想到这些卡提供的每个原子效应,将相应的那些存储在JSON字符串数组中(对于每张卡),然后在方法useCard()
中有一个巨大的开关案例,它将循环遍历数组效果。但我觉得这将是一个黑客,因为我仍然会以更复杂的方式硬编码软件中的效果。如果我要添加一个全新行为的新卡(例如将您的计算机扔出窗外),我必须更新并重新分发该软件。当我与我的主管面对此问题时,他说:“嗯,你是对的,但至少你可以写一些调试卡并立刻测试所有效果”。我还是不相信。什么是(de)序列化卡片行为的更好方法?
所有这些卡应该是同一个类的Java实例,我们称之为ActionCard。假设此类提供方法useCard()
。但是,有些卡只有在满足某些条件时才能使用,或者它们的效果需要一个参数(例如,如果卡片允许你重新掷骰子,你想重新掷骰子是什么?)。我怎样才能将所有这些复杂的行为置于useCard()
大伞下?我想过使用varargs,然后开关盒会处理参数;我还想过重载useCard()
方法,它有很多版本的版本,但它仍然有点黑客的味道。
我知道这听起来很模糊,但我无法提供有关游戏本身的许多细节;如果你需要更多的信息让我知道,我会更新/评论这个问题。但我认为同样的问题也适用于其他游戏,第一个让我想到的是Clash Royale和Magic the Gathering Online。 此外,我不需要工作代码,只需要其他人的想法和提示。提前谢谢。
编辑:我正在使用gson作为序列化库。我已经写了一些TypeAdapter
,所以我可以使用复杂的数据类型。
答案 0 :(得分:0)
一种解决方案是创建自己的编程语言"。您将卡的效果存储为字符串。然后,您可以编写一些代码来解析和解释字符串,并根据字符串更改游戏状态。一些例子是:
dealer draws 3 if hand < 5
dealer rerollDice 1
opponent loses 3
dealer ignoresRule 3 1
他们的意思是:
dealer can draw 3 cards if he has less than 5 cards
dealer re-rolls the first dice
opponent loses 3 of his cards randomly
dealer can ignore rule number 3 (whatever that maybe) for one turn
我在这里提出了这个相当简单的系统。第一个单词是效果影响的对象,第二个单词是命令以及之后的所有内容,但在单词if
之前是命令的参数。
显然这只是一个例子。您可能想要设计语言,以便它可以用来控制游戏的所有方面。一个好的开始是查看你的Player
课程(你可能有一个吗?)。你的Player
课有哪些方法?这可能是一个很好的起点。
为&#34;命令创建类&#34;比如draws
和rerollDice
,他们应该实现像Command
这样的通用界面:
interface Command {
void execute(String[] args, GameState state) {
// mutate game state here
}
}
你的语言&#34;也可以允许多个语句在程序上执行。因此,而不是创建一个名为drawsAndLoses
的新命令:
dealer drawsAndLoses 3 1
// dealer can draw 3 cards but then loses one card randomly
你可以用两个&#34;语句&#34;:
做同样的事情dealer draws 3
dealer loses 1
答案 1 :(得分:0)
最合适的概念是你的ActionCard类包含一个Effect列表,其中Effect将是一个方法perform()的接口。 当然,你必须用它们采用的参数写下所有可能的效果,并开发许多效果的实现。
结果是你的序列化必须是多态的。
要了解要反序列化的对象类型,在序列化时,还要编写对象标记。 在最简单的形式中,它可以是效果实现的完全限定名称。
这是一个简单的例子。想象一下,您将要读取一个项目列表,其中每个项目可以是字符串,整数或日期。 您的列表可以序列化为:
[
{"type": "java.lang.String", "value": "Hello"},
{"type": "java.lang.String", "value": "World"}
{"type": "java.lang.Integer", "value": 123}
{"type": "java.lang.String", "value": "Hi!"},
{"type": "java.util.Date", "value": {"year": 2018, "month": 5, "day": 12}},
{"type": "java.lang.Integer", "value": 456}
]
type字段是我们的识别标签。根据它包含的内容,您可以知道要在值字段中找到的对象类型。 当然,使用字符串,数字或枚举作为标记会更安全,特别是如果玩家可以修改序列化数据;但现在至少你有基本的想法。