如何在Java中正确地建模战舰游戏

3
我正在尝试为我们大学的“游戏”项目创建一款战舰游戏。以前我几乎所有的输出都是在Eclipse控制台中,从未真正使用过GUI界面。
首先,我创建了一个GUI类,这实际上是我的“运行”类。它加载了一个JFrame。
我有第二个类,GUIGrid,它设置了将要显示的两个游戏板的维度,并使用嵌套的for循环来从GUICells创建网格。
其中包含侦听器等,以检测鼠标的操作,并存储每个单元格的x和y坐标。我运行了一小段测试代码,所以我可以在任何网格位置上单击,并弹出窗口告诉我该单元格的确切坐标。
除了这些类之外,我还有一个Ship类,它有五个子类用于不同类型的船只,还有一个Player类,它存储玩家的名称并为他们创建一个船只对象数组供他们使用。
最后,我有我的逻辑类。我有一个GridLogic类和一个CellLogic类。前者使用嵌套的for循环创建CellLogic对象的2D数组。CellLogic类然后存储像坐标和单元格是否被攻击等信息。
我的问题(终于!)是 - 这是否是对系统建模的正确方法?当我查看CellLogic和CellGUI类时,它们似乎有相当相似的东西。另外,尽管我可以使GUI响应鼠标点击,但我确实难以将GUI连接到逻辑。例如,我不知道如何将船只添加到网格中,然后在2D数组中存储哪些位置存储船只。我希望有人告诉我,我是否至少走在了正确的轨道上,或者我是否将系统分离得太多。

你已经有很多优秀的答案了,而且你的方法相当可靠。如果你需要额外的参考,你可以在这个TicTacToe代码中找到一个基本的回合制JavaFX网格游戏。 - jewelsea
4个回答

3

虽然我认为分离听起来不错,但是我觉得可以更清晰一些。使用MVC模式,您可以清楚地定义模型(船只和网格)、控制器(逻辑)和视图(绘制网格的JFrame)。

现在基本上,模型不知道其他任何东西,控制器知道视图和模型,视图知道如何绘制模型并在用户输入时调用控制器。也就是说,当用户点击时,视图只是使用坐标和发生的事件调用控制器。控制器现在修改网格并发出重绘。

因此,在我的观点中,您可能不需要一个cellGUI类,只需要一个绘制所有内容的视图(尽管,如果您在cellgui类中存储x,y,可以将其建模...)。但是,您不需要一个celllogic类。您需要一个“更高级”的控制器,了解如何修改 整个 网格,以及如果已经有某些内容会发生什么等。


谢谢 - 我会尝试合并这两个逻辑类。 - Andrew Martin

2
过度使用子类化的趋势在大学项目中非常普遍。今天,大多数情况下都会避免使用子类化。在您的示例中,使用子类来表示船只类型并没有真正的好处。更好的设计是只使用一个名为Ship的类,该类具有一个枚举型ShipType。这样做也将使以后的评估更容易。
回答您的评论: 您的方法缺少一种包含2D网格和玩家对象(所有游戏数据)的GridModel。这个GridModelGridGUIGridLogic中都知道。 GridLogic修改GridModel,并告诉GridGui重新绘制已更改的模型。 GridGUI不会修改模型,它只是通知GridLogic发生了网格坐标x,y的单击事件。然后逻辑上的修改模型并让GUI刷新自己。有关更多详细信息,请参见模型-视图-控制器模式

谢谢 - 你对GridLogic、GridGUI、CellLogic和CellGUI的分离有什么建议吗?这样做是否太多了? - Andrew Martin

1
我猜你在这里不会得到一个确切的答案,但这是我的看法。明显是MVC模式。特别是我会将主GUI保持为一个类(JFrame,菜单等),将棋盘保持在另一个类中。它将使用Cells和Ships来绘制自身。Cells将包含信息(它们的x,y坐标,哪艘船在上面以及是否被轰炸),ship类将有其类型,从x,y到x,y的距离,用于呈现图像。然后您可以有一个部分透明的炸弹图像,以便可以在其下方看到船只。
棋盘将绘制正方形、船只,最后在其上方放置炸弹。
与其弹出窗口不如有一个调试框架,在标签上显示一些关键信息;除了运行日志之外。
控制器将是BattleShip类,从model:cells和ships获得帮助。保持通信,谁打了哪里等等分开->通过接口与Board交流,因此可以将其更改为具有新视图的Web应用程序。

0

使用监听器的模型-视图-控制器。如果您研究JavaFX(旨在跟进Java Swing),它具有更简单的“内置”更改侦听器。此外,还有一些漂亮的样式和动画效果可用,无需太多编程。

其他部分看起来不错。在继承方面退后一步。您可以实现一个功能查找/发现模型:

public interface FlightCapable { }
public class X {
    public T lookup(Class<T> intface) { }
}
FlightCapable fc = x.lookup(FlightCapable.class);
if (fc != null)
    fc.fly();  // Instead of x.fly();

这高度解耦。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接