1

背景:
我目前正在开发一款游戏,其中将有几种类型的家具,如椅子、桌子或绘画供玩家互动。为此,我创建了一个抽象类GameObject来处理所有这些对象共有的所有内容(例如绘图、保存位置变量等)。家具将有一些不同的参数,例如宽度和高度(整数),以及当用户选择与之交互时会发生什么(例如:椅子 -> 如果玩家靠近,坐下,桌子 -> 没有,绘画->检查独立于距离)。可以从菜单中创建家具,该菜单会返回所选作品的某种标识符(当前为整数)。

问题:
我应该如何实现不同的家具?
一种方法是为每件家具创建一个子类。但这有两个缺点;首先很难管理这么多类,其次当创建家具时,必须以某种方式基于标识符创建正确的 GameObject 子类(请参阅后续问题)。

对我来说最合乎逻辑的选择似乎是创建一个通用类,该类在构造函数中采用宽度和高度参数,以及当用户单击对象时可以运行的可运行/其他接口。不同的值可能会存储在数据库中并根据标识符进行检索,但不同的操作仍然会出现问题,因为 Runnables 无法存储在外部,这会导致与解决方案 1 相同的问题;许多不同的类必须为当前对象选择一个。

后续问题: 根据家具和动作的类型,似乎可能需要具有附加方法的更高级的子类。如果是这样,那么无论前一个问题的解决方案如何,根据标识符选择实施哪一个的问题仍然存在。我不想使用巨大的 switch 语句来实例化不同的类,那么有什么办法解决这个问题吗?

该游戏适用于 Android 平台,但未来可能会有 IOS 端口,因此特定于 java 的答案不是可取的,但可以接受。

4

3 回答 3

2

忘记泛型类;正如您在第一个选项中介绍的那样,您应该创建子类。关于你的缺点:

管理这么多课程会很困难

为什么?如果您创建子类,您将执行以下操作:

GameObject chair = new Chair();

如果你遵循通用模式,你会做这样的事情:

GameObject chair = new GameObject(Type.CHAIR);

创建两者的努力几乎相同,但是使用第一个可以带来更多好处。不同之处在于,如果不进行大量条件验证,您将无法使用第二种方法处理不同的操作。此外,您的核心将与现有对象高度耦合,这意味着如果您更改其中一个类,则需要更改核心,反之亦然。使用第一个选项,您可以执行以下操作:

selectedObject.makeAction();

它会根据它保留的实例调用正确的操作。如果您遵循通用方法,它将如下所示:

if(selectedObject.getType() == Type.CHAIR) {
    //do char action. Notice that this ins't even a method provided by GameObject, you will need to get this from another place, since the GameObject is generic.
}     if(selectedObject.getType() == Type.TABLE) {
     //do table action
} if....

创建家具时,必须以某种方式基于标识符创建正确的 GameObject 子类

我没明白你的意思。您不需要基于 id 创建,您只需要创建适当的类。当您创建对象时,您已经知道对象类型,您只需要实例化正确的类。

于 2012-10-18T11:08:04.003 回答
1

如果不考虑所有 if 和 but 的问题,很难为这个问题提出一个完美的设计解决方案。

但是,游戏的一个关键部分是项目(家具、绘画等)与可以对每个项目执行的操作之间的关系。这是您可以建模这种关系的方式(使用组合):

Action : 表示游戏动作的界面。包含一个名为 performAction 的方法。

SittingAction :实现Action 的具体类。代表坐着的游戏动作。实现 performAction 方法来定义执行坐姿动作的代码。

ExamineAction :实现Action 的具体类。表示检查项目的游戏动作。实现 performAction 方法以定义执行检查操作的代码。

同样,您可以为可以在游戏中执行的每种动作类型定义一个动作。

GameItem :表示游戏中项目的类。包含所有项目共有的属性,例如项目名称、宽度、宽度、深度等,以及这些属性的 getter 和 setter。GameItem '有一个' Action 类型的实例变量和一个使用 Action 参数来初始化 Action 的构造函数。GameItem 还定义了一个名为 onInteraction 的方法,您可以在用户与 GameItem 交互时调用该方法。此方法将通过调用 Action 实例变量的 performAction 方法来委派执行与 GameItem 关联的 Action 的任务。因此,任何实例化 GameItem 的类都必须将适当的 Action 传递给代表与 GameItem 关联的 Action 的 GameItem 构造函数。当用户与项目交互时,只需调用 onIneraction 方法。

GameController :监听用户事件并调用与之交互的 GameItem 上的 onIneraction 方法的类。

而已。干净简单。不需要任何 if else 语句来检查对什么项目执行什么操作。Simpy 使用适当的 Action 实例实例化您的所有 GameItem 实例,并让您的 GameController 监听用户输入,调用与之交互的 GameItem 上的 onIneraction 方法。

于 2012-10-18T17:49:29.623 回答
1

I'd definitely go with having subclasses for the differente types of furniture.

Instead of the menu returning an identifier, you may think on the menu returning the class name you need to instantiate (I suppose when displaying the menu you know which class will represent each of the entries). This way you avoid the identifier issue you are describing.

Regarding the actions that can be done on each piece, you can use interfaces :

Each furniture class will implement a set of interfaces depending on their posible actions :

Interface IExaminable {
  public <result> examine();
}

Interface IBuyable {
  public <result> buy();
}

and then you can easily check if an object is examinable with the isntanceof operator (if needed).

Hope it helps

于 2012-10-18T11:04:15.437 回答