我正在尝试使用 MVC 设计来实现游戏。但是,我遇到了一些问题。我没有在 MVC 上寻求过多的帮助(我很喜欢尝试它,尽管其中大部分都没有成功!),我现在正在与我的听众有点挣扎。
我有一个看起来像这样的抽象网格类:
public abstract class ViewAbstractGrid extends JPanel {
private final int GRID_SIZE = 10;
private ViewCell[][] cellArray = new ViewCell[GRID_SIZE][GRID_SIZE];
private ViewCell currentCell;
public ViewAbstractGrid() {
setPreferredSize(new Dimension(300, 300));
setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));
for (int x = 0; x < GRID_SIZE; x++)
for (int y = 0; y < GRID_SIZE; y++) {
currentCell = new ViewCell(x, y);
cellArray[x][y] = currentCell;
add(currentCell);
}
}
public ViewCell[][] getCellArray() {
return cellArray;
}
public abstract void addListener(MouseListener listener);
}
在我最初的游戏设计中,在实现 ViewCell 时,我为它们创建了一个 MouseListener,因此每个 ViewCell 都有自己的面板。但是,我尝试将此逻辑删除到 Controller 类中,这样,不是每个 ViewCell 都有自己的侦听器,而是整个网格只有一个侦听器。这是 ViewCell 类:
public class ViewCell extends JPanel {
private final int CELL_SIZE = 1;
public static Color backgroundColor = new Color(105, 120, 105);
private int xPos;
private int yPos;
public ViewCell(int xPos, int yPos) {
setOpaque (true);
setBorder(BorderFactory.createBevelBorder(CELL_SIZE));
setBackground(backgroundColor);
setPreferredSize(new Dimension(CELL_SIZE, CELL_SIZE));
this.xPos = xPos;
this.yPos = yPos;
}
public Color getCellGUIColor() {
return backgroundColor;
}
public int getXPos() {
return xPos;
}
public int getYPos() {
return yPos;
}
}
如您所见,它扩展了 JPanel,这意味着我创建的网格实际上填充了 100 个 JPanel。人们(包括这个论坛上的人)告诉我我可以考虑使用 JButtons,但至少最初我发现 JPanel 更容易使用。
然后我有一个扩展 ViewAbstractGrid 的具体 Player Grid 类:
public class ViewPlayerGrid extends ViewAbstractGrid {
private LogicGrid playerGridLogic;
private ViewAbstractGrid playerGrid;
private int xPos;
private int yPos;
private int numberOfPlayerShipsPlaced = 0;
public ViewPlayerGrid(LogicGrid playerGridLogic) {
this.playerGridLogic = playerGridLogic;
}
public void addListener(MouseListener listener) {
this.addMouseListener(listener);
}
这些具体的子类有两个——一个用于计算机,一个用于播放器。为简洁起见,我只包括播放器之一。
最后,我有一个如下所示的 Controller 类:
public class GameController {
private LogicGrid playerGridLogic;
private ViewAbstractGrid playerGrid;
private int xPos;
private int yPos;
private int numberOfPlayerShipsPlaced = 0;
private int numberOfComputerShipsPlaced = 0;
public GameController(LogicGrid playerGridLogic, ViewAbstractGrid playerGrid) {
this.playerGridLogic = playerGridLogic;
this.playerGrid = playerGrid;
playerGrid.addListener(new PlayerGridListener());
}
class PlayerGridListener implements MouseListener {
@Override
public void mouseEntered(MouseEvent e) {
//I know this looks wrong, but I forgot that the x and y axis on a Java grid start at the top left, not bottom left. Just go with it for now!
// Dividing by 30 as dimensions are 300 by 300. This returns results that that are between 0 and 9.
yPos = e.getX()/30;
xPos = e.getY()/30;
switch(numberOfPlayerShipsPlaced) {
case 0:
if ((yPos + 5) <= 10) {
for (int y = yPos; y < yPos + 5; y++) {
playerGrid.getCellArray()[xPos][y].setBackground(Color.GREEN);
}
}
else {
for (int y = yPos; y < 10; y++) {
playerGrid.getCellArray()[xPos][y].setBackground(Color.RED);
}
}
break;
}
}
可以看出,这个类在最后变得有点混乱。我已经删除了很多逻辑来尝试使代码更短。该游戏是为战舰设计的,上面这段代码的原因是尝试检测用户是否在网格上选择了一个可以容纳五个单元格长的水平船的单元格。如果可以,方块就会变成绿色——如果不能,它就会变成红色。
我也有“模型”,但没有包括它们,因为它们不是 GUI 设计所必需的。
基本上,问题是这样的:当我最初创建所有这些代码并将侦听器直接内置到视图中时,我无法让两个板相互通信。我还意识到我没有遵循良好的编码习惯,并试图将我的代码分解为 MVC 模式。
随之而来的一个问题是,我现在为整个网格设置了一个监听器。这样做的问题是,当我将鼠标放在一个正方形上时,它会在鼠标位于网格中的任何位置期间改变一次颜色。一旦最初的正方形(或多个正方形)改变了颜色,网格中的其他正方形都不会改变颜色,直到鼠标离开网格并再次回来。
这对我没有好处——当鼠标在方块上移动时,我需要方块改变颜色。鉴于我目前的设计,有人可以建议我如何做到这一点吗?回到每个面板都有听众的唯一方法是什么?如果是这样,这是否意味着我的听众必须在视图类中,而不是在控制器类中?此外,如果有人想在改进我的代码设计(或缩短我的问题!)之上对我提出任何建议,请随意!