在JFrame中构建扫雷板的最佳方法是什么? [英] What is the best way to build a Minesweeper Board in a JFrame?

查看:150
本文介绍了在JFrame中构建扫雷板的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是想用砖块来构造一个游戏板.我通过使用BufferedImage将图块绘制成行和列来使其工作,但是随着游戏的进行,我将需要不断更新GUI.

I am just trying to construct a gameboard with tiles to work with. I got it to work by painting the tile into rows and columns with BufferedImage, but I am going to need to constantly update the GUI as the game is played.

因此,我尝试将图块图像添加到ImageIcon,然后添加到JLabel数组,以便可以设置位置.之后,我将标签添加到gui JPanel中,但是它们之间有这些默认间隔.

So I tried to add the tile image to an ImageIcon, then to a JLabel array so that I could set the position. After that I would add the labels to the gui JPanel, but they had these default gaps between them.

我处理方法有误吗?我对Swing和Java还是很陌生

Am I approaching this incorrectly? I am very new to Swing and Java

    public static void main (String[] args) throws IOException{
    int NUMROWS = 10;
    int NUMCOLS = 10;
    int NUMMINES = 10;

    int[] mineList = GameBoard.setMines(NUMMINES, NUMROWS, NUMCOLS);
    int[][] cellNums = GameBoard.setCellNum(NUMROWS, NUMCOLS);
    boolean[][] mineField = GameBoard.getMineField(mineList, cellNums);
    int[][] adjacentMineVals = GameBoard.getAdjacentMineVals(cellNums, mineField);
    ImageIcon img = new ImageIcon(ImageIO.read(new File("GraphicFile\\Cell.png")));
    JLabel[][] label = new JLabel[NUMROWS][NUMCOLS];

    for (int i = 0; i < NUMROWS; i++){
        for (int j = 0; j < NUMCOLS; j++){
            label[i][j] = new JLabel();
            label[i][j].setIcon(img);
            label[i][j].setLocation(i*img.getIconHeight(), j*img.getIconWidth());
        }
    }
    JFrame frame = buildFrame();
    int fX = 2*frame.getInsets().left;
    int fY = (frame.getInsets().top + frame.getInsets().bottom);

    JPanel GUI = new JPanel();
    GUI.setSize(NUMCOLS*img.getIconWidth(), NUMROWS*img.getIconHeight());
    for (int i = 0; i < NUMCOLS; i++){
        for (int j = 0; j < NUMROWS; j ++){
            GUI.add(label[i][j]);

        }
    }
    frame.setSize(NUMCOLS*img.getIconWidth() + fX, NUMROWS*img.getIconHeight() + fY);
    frame.add(GUI);

}

public static JFrame buildFrame(){
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    return frame;
}

这就是给我的东西 https://i.stack.imgur.com/rX3yM.png

更新到新版本.通过使用网格并将图像作为图标放置在按钮中,已经解决了先前的问题

Update, to new version. Previous problem has been solved by using a grid and putting the images into the buttons as icons

这就是我所拥有的.它不是将带有文本的标签放在已按下的按钮上.我进行了调试,并接收了坐标和文本的输入,但只是没有将其绘制在面板上

Here is what I have. It is not putting the label with the text onto the button that has been pressed. I debugged, and its receiving input for coords and for text, but its just not painting it onto the panel

 public MinesweeperGraphics() throws IOException {
    GUI.setOpaque(false);

    for (int i = 0; i < NUMROWS; i++){
        for (int j = 0; j < NUMCOLS; j++){
            buttons[i][j] = new JButton();
            buttons[i][j].setIcon(tileUp);
            buttons[i][j].setBorder(null);
            buttons[i][j].addActionListener(this);
            buttons[i][j].setPressedIcon(tilePressed);

            GUI.add(buttons[i][j]);
        }
    }

    frame.add(GUI, BorderLayout.CENTER);
    frame.add(reset, BorderLayout.NORTH);
    reset.addActionListener(this);
    frame.setResizable(false);
    frame.pack();
    GUI.setLayout(null);

}

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource().equals(reset)){
        for (int i = 0; i < NUMROWS; i++){
            for (int j = 0; j < NUMCOLS; j++){
                buttons[i][j].setIcon(tileUp);
            }
        }
    }else {
        for (int i = 0; i < buttons.length; i++) {
            for (int j = 0; j < buttons.length; j++) {
                if (e.getSource().equals(buttons[i][j])){
                    if (mineField[i][j] == false){
                        buttons[i][j].setIcon(tileEmpty);
                        numberText.setOpaque(false);
                        numberText.setSize(buttons[i][j].getWidth(), buttons[i][j].getHeight());
                        numberText.setText("a");
                        numberText.setLocation(buttons[i][j].getLocation());
                        GUI.add(numberText);

                    } else if (mineField[i][j] == true){
                        buttons[i][j].setIcon(tileExplodedMine);
                    }
                    //isn't working here
                    buttons[i][j].setEnabled(false);
                }
            }
        }
    }
}

推荐答案

构建扫雷游戏的最佳方法是将带有动作侦听器的按钮置于网格布局中.这些按钮将同时响应键盘和鼠标输入&可以显示图标.网格布局可以在屏幕上组织它们.

The best way to build a Mine Sweeper game would be to put buttons with an action listener into a grid layout. The buttons will respond to both keyboard and mouse input & can display icons. The grid layout can organise them on-screen.

以下是GridLayout中按钮的MCVE.与上述不同之处在于:

Following is an MCVE of buttons in a GridLayout. Different to as described above is that it:

  • 不添加动作侦听器
  • 使用MineFieldModel
  • 使用文本而不是图标.

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class MineSweeper {

    private JComponent ui = null;
    private MineFieldModel mineFieldModel;
    Color[] colors = {
        Color.BLUE,
        Color.CYAN.darker(),
        Color.GREEN.darker(),
        Color.YELLOW.darker(),
        Color.ORANGE.darker(),
        Color.PINK.darker(),
        Color.MAGENTA,
        Color.RED
    };
    public final static String BOMB = new String(Character.toChars(128163));
    JButton[][] buttons;
    int size = 16;

    MineSweeper() {
        initUI();
    }

    public final void initUI() {
        if (ui != null) {
            return;
        }

        ui = new JPanel(new BorderLayout(4, 4));
        ui.setBorder(new EmptyBorder(4, 4, 4, 4));

        mineFieldModel = new MineFieldModel(16, 40);

        JPanel mineFieldContainer = new JPanel(new GridLayout(
                size, size));
        ui.add(mineFieldContainer, BorderLayout.CENTER);
        int in = 5;
        Insets insets = new Insets(in, in, in, in);
        Font f = getCompatibleFonts().firstElement().deriveFont(16f);
        buttons = new JButton[size][size];
        for (int ii = 0; ii < size; ii++) {
            for (int jj = 0; jj < size; jj++) {
                JButton b = new JButton();
                b.setMargin(insets);
                b.setFont(f);
                b.setText("?");
                if (mineFieldModel.isExposed(ii, jj)) {
                    if (mineFieldModel.isBomb(ii, jj)) {
                        b.setForeground(Color.red);
                        b.setForeground(Color.BLACK);
                        b.setText(BOMB);
                    } else if (mineFieldModel.countSurroundingMines(ii, jj) > 0) {
                        int count = mineFieldModel.countSurroundingMines(ii, jj);
                        if (count > 0) {
                            b.setForeground(colors[count - 1]);
                            b.setText("" + count);
                        }
                    } else {
                        b.setText("");
                    }
                }
                mineFieldContainer.add(b);
            }
        }
    }

    private static Vector<Font> getCompatibleFonts() {
        Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
        Vector<Font> fontVector = new Vector<>();

        for (Font font : fonts) {
            if (font.canDisplayUpTo("12345678" + BOMB) < 0) {
                fontVector.add(font);
            }
        }

        return fontVector;
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception useDefault) {
            }
            MineSweeper o = new MineSweeper();

            JFrame f = new JFrame(o.getClass().getSimpleName());
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setLocationByPlatform(true);

            f.setContentPane(o.getUI());
            f.pack();
            f.setMinimumSize(f.getSize());

            f.setVisible(true);
        };
        SwingUtilities.invokeLater(r);

    }
}

class MineFieldModel {

    public int size;
    /**
     * Records bomb locations.
     */
    boolean[][] mineField;
    /**
     * Records whether this location has been exposed.
     */
    boolean[][] fieldPlaceExposed;
    int numberMines;
    Random r = new Random();

    MineFieldModel(int size, int numberMines) {
        this.size = size;
        this.numberMines = numberMines;

        mineField = new boolean[size][size];
        fieldPlaceExposed = new boolean[size][size];
        ArrayList<Point> locations = new ArrayList<>();
        for (int ii = 0; ii < this.size; ii++) {
            for (int jj = 0; jj < size; jj++) {
                mineField[ii][jj] = false;
                // must change this to false for the actual game.
                fieldPlaceExposed[ii][jj] = true;
                Point p = new Point(ii, jj);
                locations.add(p);
            }
        }
        Collections.shuffle(locations, r);
        for (int ii = 0; ii < numberMines; ii++) {
            Point p = locations.get(ii);
            mineField[p.x][p.y] = true;
        }
    }

    public boolean isBomb(int x, int y) {
        return mineField[x][y];
    }

    public boolean isExposed(int x, int y) {
        return fieldPlaceExposed[x][y];
    }

    public int getSize() {
        return size;
    }

    public int countSurroundingMines(int x, int y) {
        int lowX = x - 1;
        lowX = lowX < 0 ? 0 : lowX;
        int highX = x + 2;
        highX = highX > size ? size : highX;

        int lowY = y - 1;
        lowY = lowY < 0 ? 0 : lowY;
        int highY = y + 2;
        highY = highY > size ? size : highY;

        int count = 0;
        for (int ii = lowX; ii < highX; ii++) {
            for (int jj = lowY; jj < highY; jj++) {
                if (ii != x || jj != y) {
                    if (mineField[ii][jj]) {
                        count++;
                    }
                }
            }
        }

        return count;
    }
}

这篇关于在JFrame中构建扫雷板的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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