2017-01-20 11 views
-2

Я просто пытаюсь построить игровое поле с плитами для работы. Я получил его для работы, рисуя плитки в строки и столбцы с помощью BufferedImage, но мне нужно постоянно обновлять графический интерфейс при игре.Каков наилучший способ построить совет по разминированию в JFrame?

Итак, я попытался добавить изображение плитки в ImageIcon, а затем в массив JLabel, чтобы установить положение. После этого я добавлю метки в gui JPanel, но у них были эти промежутки по умолчанию между ними.

Я подхожу к этому неправильно? Я очень новый для качания и 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, в новую версию. Предыдущая проблема была решена с помощью сетки и помещения изображений в кнопки в виде значков

Вот что у меня есть. Он не помещает метку с текстом на кнопку, которая была нажата. Я отлажена, и его прием входных данных для координат и для текста, но его просто не покраска на панель

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); 
       } 
      } 
     } 
    } 
} 
+2

Лучший способ построить игру Mine Sweeper бы поставить кнопки с помощью прослушивателя действий в макете сетки. Кнопки будут реагировать на ввод клавиатуры и мыши и могут отображать значки. Схема сетки может организовать их на экране. –

+1

Общий совет: 1) Для более эффективной помощи, отправьте сообщение [MCVE] или [Short, Self Contained, Correct Example] (http://www.sscce.org/). 2) Один из способов получить изображение (-ы) для примера - это горячая ссылка на изображения, видимые в [этом Q & A] (http://stackoverflow.com/q/19209650/418556). –

+0

@AndrewThompson Какие кнопки возможны? Могут ли они показать разные .png изображения вместо их по умолчанию? – Austen

ответ

1

Лучший способа построить игру Mine Sweeper бы поставить кнопки с помощью прослушивателя действий в сетку раскладка. Кнопки будут реагировать на ввод клавиатуры и мыши. & может отображать значки. Схема сетки может организовать их на экране.

Ниже приводится MCVE кнопок в GridLayout. Различный как описано выше, является то, что он:

  • Не добавляет слушателей действий
  • Использует MineFieldModel
  • использует текст вместо иконок.

enter image description here

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; 
    } 
}