重新启动扫雷艇 GUI 程序 [英] Restarting minesweeper GUI program

查看:30
本文介绍了重新启动扫雷艇 GUI 程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我制作了一个很像扫雷艇的 GUI 游戏,尽管逻辑要少得多.基本上,用户单击一个空格并查看下面是否有金子,如果没有,则显示 X.如果有,则显示金块.我想让游戏重新启动,一旦用户找到 10 个金币,所有数据都会重置.但是,我的 do while 循环没有成功.我已经注释掉了导致我出现问题的代码部分.每次我用我注释掉的东西运行程序时,当我单击第一个按钮时,它会卡住并且不会继续运行.否则,注释掉这些内容后,它应该如何工作.

问题:如何在用户发现 10 个金币后重新启动我的程序并重置数据值?另外,为什么我设置的 12x12 按钮网格与我设置 2D 按钮阵列的方式不成比例?

当我将 do while 注释掉时,游戏的效果如下:

public class NuggetPanel extends JPanel {//变量声明boolean restartGame = false;JButton[][] 按钮 = new JButton[12][12];JButton restart = new JButton("你赢了!点击重新开始游戏");整数计数 = 0;int goldFound = 0;JLabel clickCount = new JLabel("挖掘次数:" + count);JLabel goldCount = new JLabel("找到黄金:" + goldFound);//设置面板公共掘金面板(){setLayout(new GridLayout(12, 12, 2, 2));JPanel LabelPane = new JPanel();//创建按钮的二维数组for (int i = 0; i 

解决方案

另外,为什么我设置的 12x12 按钮网格与我设置 2D 按钮阵列的方式不成比例?

这是一个双重问题.JButton 具有通常不是方形的 margin 属性.此外,当您将组件添加到 GridLayout 时,所有组件的大小都相同,因此当您将 LabelPane 添加到布局时,它会强制所有按钮都在至少是宽度.

相反,使用 GridLayout 将您的按钮放在一个单独的面板上,然后使用 BorderLayout 将此和 LabelPanel 放在您的 NuggetPanel 上>,例如...

 public NuggetPanel() {setLayout(new BorderLayout());JPanel buttonPane = new JPanel(new GridLayout(12, 12, 2, 2));//创建按钮的二维数组for (int i = 0; i 

<块引用>

一旦用户发现了 10 个金币,如何让我的程序重新启动并重置数据值?

这是一个更复杂的问题,需要您改变思维方式.

actionPerfomed 在每个按钮被点击时都会被调用,但你所做的是随机化金币的位置......这将使用户几乎不可能获胜.为什么?因为可以将一块金子放在已经选中的按钮下...

 @Overridepublic void actionPerformed(ActionEvent e) {//找到哪个按钮被点击JButton buttonClicked = (JButton) e.getSource();重启游戏 = 假;重启.setVisible(false);//设置黄金数组布尔 [] 随机黄金 = 新布尔 [144];//用 10 个真实元素填充黄金数组for (int i = 0; i < randomGold.length; i++) {随机黄金[i] = 假;//将数组中的 10 个索引设置为 trueif (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 ||我 == 90 || 我 == 100) {randomGold[i] = 真;}}//随机化黄金数组Collections.shuffle(Arrays.asList(randomGold));

相反,创建一个可用于重置或初始化游戏状态的方法...

 protected void reset() {//设置黄金数组randomGold = 新布尔值 [144];//用 10 个真实元素填充黄金数组for (int i = 0; i < randomGold.length; i++) {随机黄金[i] = 假;//将数组中的 10 个索引设置为 trueif (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 ||我 == 90 || 我 == 100) {randomGold[i] = 真;}}//随机化黄金数组Collections.shuffle(Arrays.asList(randomGold));for (int i = 0; i 

这也应该在构造函数的末尾调用.这将确保游戏处于可以播放的就绪状态...

不使用 buttons[i][j].removeActionListener(this);,简单地使用 buttons[i][j].setEnabled(false); 将按钮设置为禁用状态;,这使得重置按钮更容易,因为您不需要关心按钮是否已经有一个 ActionListener 与之关联(这可能会导致您的 actionPerformed 方法为单个按钮多次调用 :P)

在您的 actionPerformed 方法结束时,您只需要检查 goldFound 的数量并调用 reset 来重置游戏...

if (goldFound == 10) {JOptionPane.showMessageDialog(NuggetPanel.this, "你赢了");重启();}

其他...

不要使用类似...的东西从 src 目录加载资源

 buttons[i][j].setIcon(new ImageIcon("./src/Missed.png"));

一旦代码被构建,这将失败.相反,您需要将资源作为嵌入资源引用并使用 Class#getResource

 buttons[i][j].setIcon(new ImageIcon(getClass().getResource("/Missed.png")));

但坦率地说,这有点浪费,您可以改为将图标定义为常量....

public static final ImageIcon MISSED_ICON = new ImageIcon(getClass().getResource("/Missed.png")));

然后在需要时简单地引用它...

 buttons[i][j].setIcon(MISSED_ICON);

就我个人而言,我更喜欢 ImageIO.read 因为它会抛出一个 IOException,但它使设置常量变得更加复杂...

另外,我可能会考虑使用某种 List 来管理按钮和黄金"位置,因为它只是使用 List#indexOf(Object) 然后每次都必须运行双循环...

I've made a GUI game that is much like minesweeper, although there is much less logic. Basically a user clicks a space and sees if there is gold underneath and if there isn't, it shows an X. If there is, it shows a gold piece. I want to make so the game restarts and all the data is reset once the user finds 10 gold pieces. However, I'm not having success with my do while loop. I've commented out the part of my code that causes me problems. Each time I run the program with the stuff that I have commented out, it gets stuck and won't continue running when I click the first button. Otherwise, with the stuff commented out, it works how it should.

Question: How can I make my program restart and the data values reset once a user uncovers 10 gold pieces? Also, why is my 12x12 button grid I've set up showing up not proportional to how I set up the 2D button array?

Here's what the game looks like when I have the do while commented out:

public class NuggetPanel extends JPanel {

    // variable declaration
    boolean restartGame = false;
    JButton[][] buttons = new JButton[12][12];
    JButton restart = new JButton("You win! Click to restart game");
    int count = 0;
    int goldFound = 0;
    JLabel clickCount = new JLabel("Number of digs: " + count);
    JLabel goldCount = new JLabel("Gold found: " + goldFound);


    // sets up the panel
    public NuggetPanel() {

        setLayout(new GridLayout(12, 12, 2, 2));
        JPanel LabelPane = new JPanel();


        //creates 2D array of buttons
        for (int i = 0; i < buttons.length; i++) {
            for (int j = 0; j < buttons[i].length; j++) {
                buttons[i][j] = new JButton("");
                buttons[i][j].addActionListener(new buttonListener());
                add(buttons[i][j]);
            }

        }



        //adds components
        LabelPane.add(clickCount);
        LabelPane.add(goldCount);
        LabelPane.add(restart);
        add(LabelPane);
        restart.setVisible(false);
    }

    // button is clicked
    private class buttonListener implements ActionListener {    

        @Override
        public void actionPerformed(ActionEvent e) {

//  do{

            // finds which button was clicked
            JButton buttonClicked = (JButton) e.getSource();

            restartGame = false;
            restart.setVisible(false);


            // sets up gold array
            Boolean[] randomGold = new Boolean[144];

            // fills gold array with 10 true elements
            for (int i = 0; i < randomGold.length; i++) {
                randomGold[i] = false;

                // sets 10 indexes in the array to true
                if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
                    randomGold[i] = true;
                }
            }

            // randomizes gold array
            Collections.shuffle(Arrays.asList(randomGold));

            // iterates through button array
            for (int i = 0; i < buttons.length; i++) {

                for (int j = 0; j < buttons[i].length; j++) {

                    if (buttonClicked == buttons[i][j]) {

                        // if there is a gold under the square, shows gold icon
                        if (randomGold[i] == true) {
                            buttons[i][j].setIcon(new ImageIcon("./src/Gold.jpg"));
                            buttons[i][j].removeActionListener(this);
                            goldFound++;
                            count++;
                            clickCount.setText("Number of digs: " + count);
                            goldCount.setText("Gold found: " + goldFound + "  ");

                        }

                        // if there is no gold under the square, shows X
                        else {
                            buttons[i][j].removeActionListener(this);
                            buttons[i][j].setIcon(new ImageIcon("./src/Missed.png"));
                            count++;
                            clickCount.setText("Number of digs: " + count);
                            goldCount.setText("Gold found: " + goldFound);
                        }

//                      if (goldFound == 10) {
//                          restart.setVisible(true);
//                      }
//
//                      if (buttonClicked == restart) {
//                          count = 0;
//                          goldFound = 0;
//                          clickCount.setText("Number of digs: " + count);
//                          for (int x = 0; i < buttons.length; i++)
//                          {
//                              for(int y = 0; j < buttons[i].length; j++)
//                              {
//                                  buttons[x][y].setIcon(null);
//                              }
//                          }
//                          restartGame = true;
//                      }

                        j = buttons[i].length - 1;
                        i = buttons.length - 1;

                    }

                }
            }
//      } while(restartGame = true);
    }
}
}

解决方案

Also, why is my 12x12 button grid I've set up showing up not proportional to how I set up the 2D button array?

This is a two fold issue. JButton has margin properties which aren't normally square. Also, when you add components to a GridLayout, ALL the components get sized the same, so when you add your LabelPane to the layout, it forces all the buttons to have at least it's width.

Instead, put your buttons onto a separate panel, using a GridLayout, and then put this and the LabelPanel onto your NuggetPanel using a BorderLayout, for example...

    public NuggetPanel() {

        setLayout(new BorderLayout());

        JPanel buttonPane = new JPanel(new GridLayout(12, 12, 2, 2));
        //creates 2D array of buttons
        for (int i = 0; i < buttons.length; i++) {
            for (int j = 0; j < buttons[i].length; j++) {
                // nb: I'd use a "blank" icon which was the same
                // size as the other icons and set it as the 
                // buttons icon, this will ensure that the 
                // buttons are always the right size...
                buttons[i][j] = new JButton("");
                buttons[i][j].setMargin(new Insets(5, 5, 5, 5));
                buttons[i][j].addActionListener(new buttonListener());
                buttonPane.add(buttons[i][j]);
            }

        }

        //adds components
        JPanel LabelPane = new JPanel();
        LabelPane.add(clickCount);
        LabelPane.add(goldCount);
        LabelPane.add(restart);

        add(buttonPane);
        add(LabelPane, BorderLayout.SOUTH);

        restart.setVisible(false);
    }

How can I make my program restart and the data values reset once a user uncovers 10 gold pieces?

This is a more complex issue and will require you to change the way you are thinking.

actionPerfomed will be called when every ANY button is clicked, but what you are doing is randomizing the location of the gold as well...this will make it almost impossible for the user to win. Why? Because it's possible to place a piece of gold under a button which as already been checked...

    @Override
    public void actionPerformed(ActionEvent e) {

        // finds which button was clicked
        JButton buttonClicked = (JButton) e.getSource();

        restartGame = false;
        restart.setVisible(false);

        // sets up gold array
        Boolean[] randomGold = new Boolean[144];

        // fills gold array with 10 true elements
        for (int i = 0; i < randomGold.length; i++) {
            randomGold[i] = false;

            // sets 10 indexes in the array to true
            if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
                randomGold[i] = true;
            }
        }

        // randomizes gold array
        Collections.shuffle(Arrays.asList(randomGold));

Instead, create a method which can be used to reset or initialise the state of the game...

    protected void reset() {
        // sets up gold array
        randomGold = new Boolean[144];

        // fills gold array with 10 true elements
        for (int i = 0; i < randomGold.length; i++) {
            randomGold[i] = false;

            // sets 10 indexes in the array to true
            if (i == 10 || i == 20 || i == 30 || i == 40 || i == 50 || i == 60 || i == 70 || i == 80 || i == 90 || i == 100) {
                randomGold[i] = true;
            }
        }

        // randomizes gold array
        Collections.shuffle(Arrays.asList(randomGold));

        for (int i = 0; i < buttons.length; i++) {
            for (int j = 0; j < buttons[i].length; j++) {
                // Reset the image icon with a blank image...
                buttons[i][j].setText("");
                buttons[i][j].setEnabled(true);
            }

        }
    }

This should be called at the end of your constructor as well. This will ensure that the game is a ready state to be played...

Instead of using buttons[i][j].removeActionListener(this);, simple set the button as disabled using buttons[i][j].setEnabled(false);, this makes it easier to reset the button, as you don't need to care if the button already has an ActionListener associated with it or not (which could lead to your actionPerformed method been called multiple times for a single button :P)

At the end of your actionPerformed method, you simply need to make a check for the number of goldFound and call reset to reset the game...

if (goldFound == 10) {
    JOptionPane.showMessageDialog(NuggetPanel.this, "You win");
    reset();
}

Additional...

Don't load resources from your src directory using something like...

 buttons[i][j].setIcon(new ImageIcon("./src/Missed.png"));

This will fail once the code is built. Instead, you need to reference the resource as an embedded resource and use Class#getResource

 buttons[i][j].setIcon(new ImageIcon(getClass().getResource("/Missed.png")));

But frankly, this is a little wasteful, you could, instead, define the icons as constants....

public static final ImageIcon MISSED_ICON = new ImageIcon(getClass().getResource("/Missed.png")));

And then simply reference it when ever you need to...

 buttons[i][j].setIcon(MISSED_ICON);

Personally, I prefer ImageIO.read as it throws an IOException, but it makes it more complicated to set up constants...

Also, I would probably consider using a List of some kind to manage the buttons and "gold" locations as it's simply to use List#indexOf(Object) then having to run through your double loop each time...

这篇关于重新启动扫雷艇 GUI 程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆