我一直在研究我的扫雷工程,我似乎遇到了一些麻烦。我的程序编译,但我的问题是在我的网格上设置地雷。我使用随机生成器设置位置,但我不知道如何在我的网格上实现它。我希望程序做的是当一个带炸弹的块被击中时,它的可见性应该改变,并且应该出现一个黑色正方形。到目前为止,这是我的代码:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
public class Minesweeper extends JFrame implements ActionListener {
public int gridRows; //
public int gridColumns; //
int mines;
private int numMines;
private int row, col;
boolean secondTime;
JMenuItem Expert, Intermediate, Easy;
JButton[][] easyGrid; // 2d array for button grid.
boolean[][] setMine = new boolean[row][col];
int numberMine[][];
public static void main(String[] args) {
// creates frame
Minesweeper gameWindow = new Minesweeper();
gameWindow.setSize(400, 400);
gameWindow.setVisible(true); // sets the visibility of the game board to true.
}
public Minesweeper() {
super("Minesweeper");
}
// class constructor.
public void init() {
// variables set the size of the playing board
int rowsX = 9;
int columnsY = 9;
gridRows = rowsX;
gridColumns = columnsY;
setLayout(new GridLayout(rowsX, columnsY)); // creates and sets a grid format.
easyGrid = new JButton[rowsX][columnsY]; // sets the grid size from the parameters given
// loops through rows and columns to draw grid.
for (int i = 0; i < columnsY; i++) {
for (int j = 0; j < rowsX; j++) {
row = i;
col = j;
easyGrid[i][j] = new JButton(""); //creates new button
easyGrid[i][j].addActionListener(this); // assigns an action to the grid buttons
add(easyGrid[i][j]); // adds buttons to the game board
}
}
JMenu gameMenu = new JMenu("GameOptions"); // creates menu option
// creating each option under the JMenuBar (toolBar)
JMenuItem easyChoice = new JMenuItem("Beginner(9x9)");
easyChoice.addActionListener(this);
gameMenu.add(easyChoice); // adds choice option to the drop down menu
Easy = easyChoice;
// button selects a 16 by 16 grid for intermediate players
JMenuItem mediumChoice = new JMenuItem("Intermediate(16x16)");
mediumChoice.addActionListener(this);
gameMenu.add(mediumChoice); // adds choice option to the drop down menu
Intermediate = mediumChoice;
// button selects a 16 by 30 grid for more advanced players
JMenuItem hardChoice = new JMenuItem("Advanced(16x30)");
hardChoice.addActionListener(this);
gameMenu.add(hardChoice); // adds choice option to the drop down menu
Expert = hardChoice;
JMenuBar toolBar = new JMenuBar();
toolBar.add(gameMenu);
setJMenuBar(toolBar);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // sets the button for exiting the program.
pack(); // set frame size.
}
// lays out the mines on the grid.
public void createMines() {
java.util.Random rand = new java.util.Random(); // Random class
int rndm1;
int rndm2; // gives the co-ordinates of the mine
for (int countBomb = 0; countBomb <= mines; countBomb++) {
rndm1 = rand.nextInt(8) + 1; // pick a row (+1 for buffer compensation)
rndm2 = rand.nextInt(8) + 1; // pick a col
if (!easyGrid[gridRows][gridColumns].equals(setMine[rndm1][rndm2])) {
setMine[rndm1][rndm2] = true;
easyGrid[rndm1][rndm2].setVisible(true);
// checks if there is no bomb present already.
}
}
}
// this method redirects the user based on a selection made from the drop down menu
public void actionPerformed(ActionEvent event) {
if (event.getSource() instanceof JButton) {
((JButton) event.getSource()).setVisible(false);
}
if (event.getSource() == Easy) {
gridRows = 30;
gridColumns = 16;
mines = 99;
secondTime = true;
init();
} else if (event.getSource() == Intermediate) {
gridColumns = gridRows = 16;
mines = 40;
secondTime = true;
init();
} else if (event.getSource() == Expert) {
gridRows = gridColumns = 8;
mines = 10;
secondTime = true;
init();
}
}
}
答案 0 :(得分:4)
看起来你正试图在一个类中实现你的程序,我强烈建议你不要这样做,而是将代码细分为几个按自然划分划分的类。
当我自己完成此操作时,我首先创建了两个“模型”非GUI类及其各自的GUI类,以尝试将逻辑从显示中分离出来。
您可以在此处查看我的代码:minesweeper-action-events
例如,一个类被称为MineCellModel,它具有三个绑定的布尔属性或状态,标记(用户右键单击它以“标记”它并且按钮不能被按下),按下,和mineBlown,以及一个非绑定财产/州:开采。后者没有约束,因为它在游戏过程中不会改变,因此在游戏过程中不需要使用PropertyChangeListener来监听它。
此模型随后由MineCell对象使用,该类扩展JPanel并保存JLabel(用于保存基础数字)和最初显示的JButton。它为它的模型添加了一个PropertyChangeListener来监听状态的变化,并通过改变它的显示来响应状态的变化。例如,如果标记状态变为true,则MineCell将在JButton上显示标记图像,该按钮将对按钮按下无响应。我使用CardLayout取得了很好的成功,以便最好地交换矿井电池的显示效果。例如,所有单元格最初都可以显示一个JButton,其Icon可以通过鼠标单击鼠标右键单击进行交换。然后当用鼠标左键单击按钮(使用ActionListener)时,我使用CardLayout显示一个JLabel,它有一个我的图像图标或显示一个数字。
还有一个MineCellGridModel,它保存整个网格的非GUI逻辑。它包含一个MineCellModel对象的二维数组以及一个地雷的ArrayList。它还将PropertyChangeListener添加到它保存的所有MineCellModel中,以检查按钮按下事件。如果它们发生,它会检查游戏是否获胜。在这里它也会对矿井爆炸事件或游戏丢失做出反应,并有网格显示所有爆炸的地雷。最后它对按钮按下做出反应,其中矿井单元模型的值为0(它没有邻居是地雷)并且在这种情况下它递归地调用围绕它的所有采矿单元模型上的pressedAction,导致级联的冷却效果按钮按下有时会从网格上清除大量按钮。
然后是一个MineCellGrid,网格的GUI视图类,它使用上面的类作为模型,最后是一个MineSweeper类,它将整个shebang放在一起并在JFrame中显示。
关于随机化地雷,我的每个类都有一个reset()方法,将其设置回其起始状态,这包括MineCellGridModel类,该类随机化一个ArrayList,该ArrayList包含一个布尔数组列表,每个类别一个网格中的单元格。它只是简化了arraylist,然后遍历使用数组列表分配地雷的cellModelGrid。然后我再次遍历cellModelGrid并且如果我找到一个已经挖掘的单元格,我会增加其直接邻居的“值” - 跟踪挖掘了多少邻居的数字:
public void reset() {
buttonsRemaining = (maxRows * maxCols) - mineNumber;
// randomize the mine location
Collections.shuffle(mineList);
// reset the model grid and set mines
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
cellModelGrid[r][c].reset();
cellModelGrid[r][c].setMined(mineList.get(r
* cellModelGrid[r].length + c));
}
}
// advance value property of all neighbors of a mined cell
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
if (cellModelGrid[r][c].isMined()) {
int rMin = Math.max(r - 1, 0);
int cMin = Math.max(c - 1, 0);
int rMax = Math.min(r + 1, cellModelGrid.length - 1);
int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].incrementValue();
}
}
}
}
}
}
答案 1 :(得分:2)
因为它实现了一个双状态按钮,JToggleButton
可能是一个有用的替代方案。您可以从相关的game获得一些想法。
答案 2 :(得分:1)
修改强> 我刚刚意识到JButton有一个图标字段,您可以将其用于图标。
也许有一个for循环来创建一个方形图像按钮网格,可以找到一种方法来制作图像按钮here,尽管你可能会发现很多带有现成gui元素的库。
我会使用2d数组来存储按钮。每个按钮都有一些字段,例如:
boolean revealed = false; //default value
boolean isMine = false; //default value
然后你可以改变按钮图形来显示我的/旗帜或其他什么,由鼠标点击事件处理程序调用。