之前得到了很好的帮助后,我完成了我的扫雷游戏。但是,有一个问题我无法弄清楚。游戏本身运行良好,但是,我有一个选项让用户改变难度设置(初学者,中级,高级)这让我感到悲伤。用户从JMenuBar中选择“Game”,然后从下拉菜单中选择“Change Difficulty”。这将调用方法selectDifficulty(),它打开一个JOptionMessageBox,它使用JRadioButtons让用户选择4个选项中的一个(第4个是Custom - 但是我还没有实现它)。用户第一次更改难度模式时,该对话框似乎正常工作。然而,当用户试图第二次或更多次改变难度时,游戏实施设置然后再次出现对话框并且促使用户再次选择难度。这有时在离开之前重复两次,而在其他时间最多重复4或5次。 我很感激任何帮助,因为我不知道为什么会这样。
另外,我也很感激如何改善难度设置的变化。目前,代码删除了JPanel和minefield(由Buttons组成)并使用新的难度设置重新实例化按钮/ Japanels。有没有办法让这个更有效率?
有一个逻辑类和一个GUI玻璃。上述两个问题都存在于GUI类中。
private void selectDifficulty() {
group.add(b1);
group.add(b2);
group.add(b3);
group.add(b4);
b1.setSelected(true);
Object[] array = {new JLabel("Select Difficulty"),b1,b2,b3,b4};
JOptionPane.showMessageDialog(null, array);
if (b1.isSelected()) {
if (mode == 1){
rw = 9;
rh = 9;
mode = 1;
}else if(mode == 2){
rw = 15;
rh = 15;
mode = 1;
}else {
rw = 20;
rh = 20;
mode = 1;
}
start(9,9);
}else if (b2.isSelected()) {
if (mode == 1){
rw = 9;
rh = 9;
mode = 2;
}else if(mode == 2){
rw = 15;
rh = 15;
mode = 2;
}else {
rw = 20;
rh = 20;
mode = 2;
}
start(15,15);
}else if (b3.isSelected()) {
if (mode == 1){
rw = 9;
rh = 9;
mode = 3;
}else if(mode == 2){
rw = 15;
rh = 15;
mode = 3;
}else {
rw = 20;
rh = 20;
mode = 3;
}
start(20,20);
}
}
完整代码: GUI CLASS
import java.awt.* ;
import java.awt.event.* ;
import javax.swing.* ;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
public class MineSweeperGUI extends JFrame implements MouseListener {
MinesweeperLogic logicClass = new MinesweeperLogic();
JButton newGameButton = new JButton ("New Game");
JMenuItem optionsButton = new JMenuItem ("Change Difficulty");
JRadioButton b1 = new JRadioButton ("Beginner: 9 X 9 Grid (10 Mines)");
JRadioButton b2 = new JRadioButton ("Intermediate: 15 X 15 Grid (36 Mines)");
JRadioButton b3 = new JRadioButton ("Advanced: 20 X 20 Grid (80 Mines)");
JRadioButton b4 = new JRadioButton ("Custom");
ButtonGroup group = new ButtonGroup();
JMenuItem aboutButton = new JMenuItem ("About Minesweeper");
JPanel p = new JPanel();
JPanel p2 = new JPanel();
JPanel p3 = new JPanel();
int w, h, rw = 0, rh = 0, mode = 1;
public void MineSweeper(int width, int height) {
//setupI();
w = width;
h = height;
logicClass.startNewGame(w, h);
GridLayout layout = new GridLayout (w, h);
p2.setLayout(new BorderLayout());
p.setLayout(layout);
p2.add(p, BorderLayout.CENTER);
for(int x = 0 ; x < w ; x++) {
for(int y = 0 ; y < h ; y++) {
logicClass.label[x][y] = new Button();
logicClass.label[x][y].setPreferredSize(new Dimension(20,20));
logicClass.label[x][y].setBackground(new Color(33,58,156));
logicClass.label[x][y].addMouseListener (this);
p.add(logicClass.label[x][y]);
}
}
JMenuBar mb = new JMenuBar();
JMenu m = new JMenu("Game");
JMenu m2 = new JMenu("Help");
m.add(optionsButton);
m2.add(aboutButton);
mb.add(m);
mb.add(m2);
p2.add(p3, BorderLayout.PAGE_START);
newGameButton.setPreferredSize (new Dimension(87, 20));
newGameButton.setFont(new Font("sansserif",Font.BOLD,11));
newGameButton.setForeground(Color.black);
newGameButton.setBackground(new Color(235,52,52));
Border thickBorder = new LineBorder(Color.black, 2);
newGameButton.setBorder(thickBorder);
p3.add(newGameButton);
newGameButton.addMouseListener(this);
optionsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
selectDifficulty();
}
});
this.setJMenuBar(mb);
this.add(p2);
this.pack();
this.setVisible(true);
}
private void start(int width, int height){
p2.remove(p);
for(int x = 0 ; x < rw ; x++) {
for(int y = 0 ; y < rh ; y++) {
p.remove(logicClass.label[x][y]);
}
}
p2.remove(p3);
p3.remove(newGameButton);
this.remove(p2);
MineSweeper(width, height);
}
private void lose() {
JOptionPane.showMessageDialog(this, "GAME OVER - YOU LOSE! Starting New Game", "Game Over", JOptionPane.INFORMATION_MESSAGE);
newGame();
}
private void win() {
JOptionPane.showMessageDialog(this, "YOU WIN! Starting New Game", "CONGRATULATIONS", JOptionPane.INFORMATION_MESSAGE);
newGame();
}
private void newGame() {
if(mode==1){
rw = 9;
rh = 9;
start(9,9);
}else if(mode==2){
rw = 15;
rh = 15;
start(15,15);
}else{
rw = 20;
rh = 20;
start(20,20);
}
}
public void mouseClicked(MouseEvent e) {
if(e.getSource() == newGameButton) {
if(e.getButton() == e.BUTTON1) {
newGame();
}
}
for (int x = 0 ; x < w; x++) {
for (int y = 0 ; y < h; y++) {
if(e.getSource() == logicClass.label[x][y]) {
if(e.getButton() == e.BUTTON1) {
if(logicClass.openCell(x, y) == false) {
lose();
} else {
for (int q = 0; q < w; q++) {
for (int j = 0; j < h; j++) {
if (logicClass.label[q][j].getBackground()==Color.green) {
win();
}
}
}
}
}else if(e.getButton() == e.BUTTON3) {
logicClass.markCell(x, y);
}
}
}
}
}
private void selectDifficulty() {
group.add(b1);
group.add(b2);
group.add(b3);
group.add(b4);
b1.setSelected(true);
Object[] array = {new JLabel("Select Difficulty"),b1,b2,b3,b4};
JOptionPane.showMessageDialog(null, array);
if (b1.isSelected()) {
if (mode == 1){
rw = 9;
rh = 9;
mode = 1;
}else if(mode == 2){
rw = 15;
rh = 15;
mode = 1;
}else {
rw = 20;
rh = 20;
mode = 1;
}
start(9,9);
}else if (b2.isSelected()) {
if (mode == 1){
rw = 9;
rh = 9;
mode = 2;
}else if(mode == 2){
rw = 15;
rh = 15;
mode = 2;
}else {
rw = 20;
rh = 20;
mode = 2;
}
start(15,15);
}else if (b3.isSelected()) {
if (mode == 1){
rw = 9;
rh = 9;
mode = 3;
}else if(mode == 2){
rw = 15;
rh = 15;
mode = 3;
}else {
rw = 20;
rh = 20;
mode = 3;
}
start(20,20);
}
}
public static void main(String[]args) {
MineSweeperGUI guiClass = new MineSweeperGUI();
guiClass.MineSweeper(9,9);
}
public void mouseEntered(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
}
逻辑课程: import java.awt。*;
public class MinesweeperLogic {
public int width, height;
private int w, h, maxBombs;
private boolean mine[][];
private boolean flag[][];
private boolean isClicked[][];
private boolean isZero[][];
private boolean marked;
MineSweeperGUI guiClass;
Button[][] label;
private int surBombs;
private String temp;
private double mineRatio;
public void startNewGame(int width, int height) {
w = width;
h = height;
label = new Button[w][h];
mine = new boolean[w][h];
flag = new boolean[w][h];
isClicked = new boolean[w][h];
isZero = new boolean[w][h];
if ( (w*h) <= 81) {
mineRatio = 0.13;
}else if ( (w*h) <= 255) {
mineRatio = 0.16;
}else {
mineRatio = 0.2;
}
maxBombs = (int) Math.floor (w * h * mineRatio);
for (int i = 0; i < maxBombs; i++) {
int x = (int) (Math.random() * w);
int y = (int) (Math.random() * h);
if (mine[x][y] == false) {
mine[x][y] = true;
isClicked[x][y] = false;
flag[x][y] = false;
isZero[x][y] = false;
} else {
i--;
}
}
}
int getWidth() {
return w;
}
int getHeight() {
return h;
}
boolean openCell(int x, int y) {
isClicked[x][y] = true;
if (mine[x][y] == true && flag[x][y] == false) {
lose();
return false;
} else if (getValue(x, y) > 0 && flag[x][y] == false) {
temp = Integer.toString (getValue(x, y));
label[x][y].setLabel (temp);
label[x][y].setBackground (new Color (111,184,252));
checkWin();
return true;
} else if (getValue(x, y) == 0 && flag[x][y] == false) {
for (int q = x-1; q <= x+1; q++) {
if(q < 0 || q >= w) {
continue;
}
for (int i = y-1; i <= y+1; i++) {
if(i < 0 || i >= h || flag[q][i] == true) { // makes sure that it wont have an error for buttons next to the wall
continue;
}
label[q][i].setBackground(new Color (111,184,252));
if (getValue(q, i) != 0) { // opens surrounding cells that have mines around them (max 8 cells)
temp = Integer.toString (getValue(q, i));
label[q][i].setLabel (temp);
isClicked[q][i] = true;
} else {
for (int k = x-1; k <= x+1; k++) {
if(k < 0 || k >= w) {
continue;
}
for (int m = y-1; m <= y+1; m++) {
if (m < 0 || m >= h || flag[k][m] == true) { // makes sure that it wont have an error for buttons next to the wall
continue;
}
if (isClicked[k][m] == false && getValue(k, m) == 0) { // recursively continues to open all surrounding cells with no mines around them
openCell(k, m);
}
}
}
}
}
}
checkWin();
return true;
} else {
return true;
}
}
boolean markCell(int x, int y) {
if (flag[x][y] == true) {
flag[x][y] = false;
label[x][y].setLabel ("");
label[x][y].setForeground (Color.black);
label[x][y].setFont (new Font (null, Font.PLAIN, 12));
return false;
}
if (isClicked[x][y] == false && flag[x][y] == false) {
flag[x][y] = true;
label[x][y].setFont (new Font ("sansserif", Font.BOLD, 14));
label[x][y].setLabel ("<|");
label[x][y].setForeground (Color.red);
}
if (mine[x][y] == true) {
return true;
} else {
return false;
}
}
boolean isOpen(int x, int y) {
if (isClicked[x][y] == false) {
return false;
} else {
return true;
}
}
boolean isMarked(int x, int y) {
if (flag[x][y] == true) {
return true;
} else {
return false;
}
}
int getValue(int x, int y) {
if (mine[x][y] == true) {
return -1;
} else {
return neighborBombs(x, y);
}
}
private int neighborBombs(int x, int y) { // checks surrounding 8 squares for number of bombs (it does include itself, but has already been checked for a bomb so it won't matter)
surBombs = 0;
for (int q = x-1; q <= x+1; q++) {
if (q < 0 || q >= w) {
continue;
}
for (int i = y-1; i <= y+1; i++) {
if (i < 0 || i >= h) { // makes sure that it wont have an error for buttons next to the wall
continue;
}
if (mine[q][i] == true) {
surBombs++;
}
}
}
return surBombs;
}
private void lose() {
for (int q = 0; q < w; q++) {
for (int j = 0; j < h; j++) {
if (mine[q][j] == true) {
if (label[q][j].getLabel().equals ("<|")) {
label[q][j].setBackground (Color.green);
} else {
label[q][j].setBackground (Color.red);
label[q][j].setLabel ("*");
label[q][j].setForeground (Color.black);
}
}
}
}
}
private void checkWin() {
int count = 0;
int count2 = 0;
for (int i = 0; i < w; i++){
for (int j = 0; j < h; j++) {
if (isClicked[i][j] == true){
count++;
}
if (mine[i][j] == true){
count2++;
}
}
}
if ( (count + count2) == (w * h) ){
win();
}
}
private void win() {
for (int q = 0; q < w; q++) {
for (int j = 0; j < h; j++) {
if (mine[q][j] == true) {
label[q][j].setBackground (Color.green);
label[q][j].setForeground (Color.red);
label[q][j].setFont (new Font ("sansserif", Font.BOLD, 14));
label[q][j].setLabel ("<|");
}
}
}
}
}
答案 0 :(得分:1)
您在MineSweeper(width, height)
的{{1}}结束时拨打start
(因为它是一种方法应该是小写)。
selectDifficulty
创建所有新组件。 MineSweeper
未创建新版,因此您向其添加另一个 optionsButton
。当您按下按钮时,每个ActionListener
都会被调用,因此ActionListener
被调用的次数越来越多。
最简单的解决方法是将此selectDifficulty
添加到ActionListener
的构造函数中,但您应该重构源代码,以便尽可能只创建一次所有组件。至少整个菜单应该转到构造函数。
答案 1 :(得分:0)
尝试设置菜单组件(JMenuBar和子项)一次,而不是每次调用MineSweeper
。我认为这是一个构造函数,顺便说一句,所以它也可能会混淆其他Java开发人员。
这是因为actionPerformed
可能会被多次调用。
答案 2 :(得分:0)
你使它变得非常复杂,Java是一种面向对象的语言,试图根据这些对象的属性/动作将你的工作分成对象。
无论如何,两个建议你的难度对话。
JDialog
的OptionsDialog。在OptionsDialog的构造函数中,发送对父框架的引用。设置难度后,在父母上调用一个方法来设置难度。