diff --git a/.classpath b/.classpath index fe80859..07b86b3 100644 --- a/.classpath +++ b/.classpath @@ -1,11 +1,11 @@ - + diff --git a/res/Flag.ico b/res/Flag.ico deleted file mode 100644 index 3bda547..0000000 Binary files a/res/Flag.ico and /dev/null differ diff --git a/res/Mine.ico b/res/Mine.ico deleted file mode 100644 index 21bddb1..0000000 Binary files a/res/Mine.ico and /dev/null differ diff --git a/res/Mine2.ico b/res/Mine2.ico deleted file mode 100644 index 84b5963..0000000 Binary files a/res/Mine2.ico and /dev/null differ diff --git a/res/Mine3.ico b/res/Mine3.ico deleted file mode 100644 index 726dc08..0000000 Binary files a/res/Mine3.ico and /dev/null differ diff --git a/res/Mine4.ico b/res/Mine4.ico deleted file mode 100644 index 5e1aed0..0000000 Binary files a/res/Mine4.ico and /dev/null differ diff --git a/res/Smiley.ico b/res/Smiley.ico deleted file mode 100644 index d251eab..0000000 Binary files a/res/Smiley.ico and /dev/null differ diff --git a/res/Smiley1.ico b/res/Smiley1.ico deleted file mode 100644 index c33e93a..0000000 Binary files a/res/Smiley1.ico and /dev/null differ diff --git a/res/Smiley2.ico b/res/Smiley2.ico deleted file mode 100644 index 7a49a43..0000000 Binary files a/res/Smiley2.ico and /dev/null differ diff --git a/res/Smiley3.ico b/res/Smiley3.ico deleted file mode 100644 index 7975f49..0000000 Binary files a/res/Smiley3.ico and /dev/null differ diff --git a/res/Tile.ico b/res/Tile.ico deleted file mode 100644 index 316d900..0000000 Binary files a/res/Tile.ico and /dev/null differ diff --git a/res/Tile2.ico b/res/Tile2.ico deleted file mode 100644 index 6872dcb..0000000 Binary files a/res/Tile2.ico and /dev/null differ diff --git a/res/Tile3.ico b/res/Tile3.ico deleted file mode 100644 index eb9d7fc..0000000 Binary files a/res/Tile3.ico and /dev/null differ diff --git a/res/Tile4.ico b/res/Tile4.ico deleted file mode 100644 index cfe2139..0000000 Binary files a/res/Tile4.ico and /dev/null differ diff --git a/res/flag.png b/res/flag.png new file mode 100644 index 0000000..70bde50 Binary files /dev/null and b/res/flag.png differ diff --git a/res/mine.png b/res/mine.png new file mode 100644 index 0000000..658d93b Binary files /dev/null and b/res/mine.png differ diff --git a/res/mine2.png b/res/mine2.png new file mode 100644 index 0000000..47fe196 Binary files /dev/null and b/res/mine2.png differ diff --git a/res/mine3.png b/res/mine3.png new file mode 100644 index 0000000..b707ffd Binary files /dev/null and b/res/mine3.png differ diff --git a/res/mine4.png b/res/mine4.png new file mode 100644 index 0000000..c529c82 Binary files /dev/null and b/res/mine4.png differ diff --git a/res/smiley.png b/res/smiley.png new file mode 100644 index 0000000..f3dac13 Binary files /dev/null and b/res/smiley.png differ diff --git a/res/smiley1.png b/res/smiley1.png new file mode 100644 index 0000000..40132d3 Binary files /dev/null and b/res/smiley1.png differ diff --git a/res/smiley2.png b/res/smiley2.png new file mode 100644 index 0000000..6487c0f Binary files /dev/null and b/res/smiley2.png differ diff --git a/res/smiley3.png b/res/smiley3.png new file mode 100644 index 0000000..f736de4 Binary files /dev/null and b/res/smiley3.png differ diff --git a/res/tile.png b/res/tile.png new file mode 100644 index 0000000..d66d495 Binary files /dev/null and b/res/tile.png differ diff --git a/res/tile2.png b/res/tile2.png new file mode 100644 index 0000000..9e9ceb1 Binary files /dev/null and b/res/tile2.png differ diff --git a/res/tile3.png b/res/tile3.png new file mode 100644 index 0000000..706eb4d Binary files /dev/null and b/res/tile3.png differ diff --git a/res/tile4.png b/res/tile4.png new file mode 100644 index 0000000..164a82a Binary files /dev/null and b/res/tile4.png differ diff --git a/src/dev/kske/minesweeper/Board.java b/src/dev/kske/minesweeper/Board.java index a1a0803..2580511 100644 --- a/src/dev/kske/minesweeper/Board.java +++ b/src/dev/kske/minesweeper/Board.java @@ -1,12 +1,17 @@ package dev.kske.minesweeper; import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; +import java.util.HashMap; +import java.util.Map; import java.util.Random; -import javax.swing.JFrame; +import javax.swing.JPanel; /** * Project: Minesweeper
@@ -14,23 +19,34 @@ import javax.swing.JFrame; * Created: 22.03.2019
* Author: Kai S. K. Engelbart */ -public class Board { +public class Board extends JPanel { - private int tileSize, width, height; + private static final long serialVersionUID = -279269871397851420L; + private static final int tileSize = 32; + + private static Map icons; + + private int width, height; private Rectangle screen; private GameState gameState; private int mines, activeTiles, flaggedTiles; private Tile[][] board; - private final JFrame viewport; + static { + icons = new HashMap<>(); + final String[] names = { "mine2", "mine4", "tile", "tile3", "flag" }; + for (String name : names) { + icons.put(name, TextureLoader.loadScaledImage(name, tileSize)); + } + } - public Board(int x, int y, int width, int height, int tileSize, int mines, JFrame viewport) { - this.tileSize = tileSize; - this.width = width; - this.height = height; - screen = new Rectangle(x, y, x + width * tileSize, y + height * tileSize); - this.viewport = viewport; + public Board(int x, int y, int width, int height, int mines) { + // Not using a layout manager + super(null); + this.width = width; + this.height = height; + screen = new Rectangle(x, y, x + width * tileSize, y + height * tileSize); gameState = GameState.ACTIVE; this.mines = mines; @@ -43,6 +59,56 @@ public class Board { board[i][j] = new Tile(); } + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + for (int i = 0; i < width; i++) + for (int j = 0; j < height; j++) { + Tile tile = board[i][j]; + int x = screen.x + i * tileSize, y = screen.y + j * tileSize; + + // Draw background with grid + g.setColor(Color.gray); + g.fillRect(x, y, x + tileSize, y + tileSize); + g.setColor(Color.black); + g.drawRect(x, y, x + tileSize, y + tileSize); + + // Draw all mines when the game is won or lost + switch (gameState) { + case LOST: + // Draw tile with normal mine + g.drawImage(icons.get("mine2"), x, y, this); + break; + case WON: + // Draw tile with diffused mine + g.drawImage(icons.get("mine4"), x, y, this); + break; + default: + if (tile.isTouched()) { + + // Draw tile with mine + if (tile.isMine()) g.drawImage(icons.get("mine2"), x, y, this); + + // Draw flagged tile + else if (tile.isDrawSurroundingMines() && tile.getSurroundingMines() > 0) { + // Draw number of surrounding mines + String numStr = String.valueOf(tile.getSurroundingMines()); + FontMetrics fm = g.getFontMetrics(); + int w = fm.stringWidth(numStr), h = fm.getHeight(); + g.setFont(new Font("Helvetica", Font.PLAIN, 12)); + g.drawString(numStr, x + tileSize / 2 - w / 2, y + tileSize / 2 - h / 2); + } + } + + // Draw flagged tile + else if (tile.isFlagged()) g.drawImage(icons.get("flag"), x, y, this); + + // Draw normal tile + else g.drawImage(icons.get("tile"), x, y, this); + } + } + } + public Point getTilePos(int x, int y) { return new Point((x - screen.x) / tileSize, (y - screen.y) / tileSize); } @@ -95,7 +161,7 @@ public class Board { touchTile(i, j); // Redraw the touched tile - drawTile(n, m); + repaint(n * tileSize, m * tileSize, (n + 1) * tileSize, (n + 1) * tileSize); } } @@ -109,28 +175,7 @@ public class Board { tile.setFlagged(true); flaggedTiles++; } - drawTile(n, m); + repaint(n * tileSize, m * tileSize, (n + 1) * tileSize, (n + 1) * tileSize); } } - - public void draw() { - for(int i = 0; i < width; i++) - for (int j = 0; j < height; j++) - drawTile(i, j); - } - - public void drawTile(int n, int m) { - Tile tile = board[n][m]; - int x = screen.x + n * tileSize, y = screen.y + m * tileSize; - Graphics g = viewport.getGraphics(); - - // Draw background with grid - g.setColor(Color.gray); - g.fillRect(x, y, x + tileSize, y + tileSize); - g.setColor(Color.black); - g.drawRect(x, y, x + tileSize, y + tileSize); - - // Draw all mines if the game is lost - // if(gameState == GameState.LOST) - } } diff --git a/src/dev/kske/minesweeper/Minesweeper.java b/src/dev/kske/minesweeper/Minesweeper.java index 14ac0eb..8af2231 100644 --- a/src/dev/kske/minesweeper/Minesweeper.java +++ b/src/dev/kske/minesweeper/Minesweeper.java @@ -1,8 +1,15 @@ package dev.kske.minesweeper; +import java.awt.BorderLayout; import java.awt.EventQueue; +import java.awt.event.KeyEvent; +import javax.swing.JButton; import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; /** * Project: Minesweeper
@@ -12,6 +19,8 @@ import javax.swing.JFrame; */ public class Minesweeper { + private static final String VERSION = "1.0 JE"; + private JFrame mframe; private Board board; @@ -50,8 +59,44 @@ public class Minesweeper { mframe.setBounds(100, 100, 450, 300); mframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - board = new Board(0, 0, 10, 10, 32, 10, mframe); - board.draw(); + createMenuBar(); + + board = new Board(0, 0, 10, 10, 10); + mframe.getContentPane().add(board); + + JButton btnRestart = new JButton("Restart"); + mframe.getContentPane().add(btnRestart, BorderLayout.NORTH); } + private void createMenuBar() { + var menubar = new JMenuBar(); + + var gameMenu = new JMenu("Game"); + var aboutMenuItem = new JMenuItem("About"); + + var easyMenuItem = new JMenuItem("Easy"); + var mediumMenuItem = new JMenuItem("Medium"); + var hardMenuItem = new JMenuItem("Hard"); + var customMenuItem = new JMenuItem("Custom"); + + gameMenu.setMnemonic(KeyEvent.VK_G); + easyMenuItem.setMnemonic(KeyEvent.VK_E); + mediumMenuItem.setMnemonic(KeyEvent.VK_M); + hardMenuItem.setMnemonic(KeyEvent.VK_H); + customMenuItem.setMnemonic(KeyEvent.VK_C); + + aboutMenuItem.addActionListener((event) -> { + JOptionPane.showMessageDialog(board, "Minesweeper version " + VERSION + "\nby Kai S. K. Engelbart"); + }); + + gameMenu.add(easyMenuItem); + gameMenu.add(mediumMenuItem); + gameMenu.add(hardMenuItem); + gameMenu.addSeparator(); + gameMenu.add(customMenuItem); + menubar.add(gameMenu); + menubar.add(aboutMenuItem); + + mframe.setJMenuBar(menubar); + } } diff --git a/src/dev/kske/minesweeper/TextureLoader.java b/src/dev/kske/minesweeper/TextureLoader.java new file mode 100644 index 0000000..7059649 --- /dev/null +++ b/src/dev/kske/minesweeper/TextureLoader.java @@ -0,0 +1,38 @@ +package dev.kske.minesweeper; + +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +/** + * Project: Minesweeper
+ * File: TextureLoader.java
+ * Created: 25.03.2019
+ * Author: Kai S. K. Engelbart + */ +public class TextureLoader { + + private TextureLoader() {} + + /** + * Loads an image from the resource folder and scales it to a square. + * + * @param name The name of the file without the PNG extension in the resource + * folder + * @param scale The side length of the square to which the image will be scaled + * @return The scaled image + */ + public static Image loadScaledImage(String name, int scale) { + BufferedImage in = null; + try { + in = ImageIO.read(new File("res" + File.separator + name + ".png")); + } catch (IOException e) { + e.printStackTrace(); + } + Image scaled = in.getScaledInstance(scale, scale, Image.SCALE_SMOOTH); + return scaled; + } +} diff --git a/src/dev/kske/minesweeper/Tile.java b/src/dev/kske/minesweeper/Tile.java index 38f48a0..ccfa7e1 100644 --- a/src/dev/kske/minesweeper/Tile.java +++ b/src/dev/kske/minesweeper/Tile.java @@ -1,13 +1,5 @@ package dev.kske.minesweeper; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import javax.imageio.ImageIO; - /** * Project: Minesweeper
* File: Tile.java
@@ -16,27 +8,11 @@ import javax.imageio.ImageIO; */ public class Tile { - private static Map icons; - private boolean mine, flagged, touched; private boolean drawSurroundingMines; private int surroundingMines; - static { - icons = new HashMap<>(); - final String[] names = { "Mine2", "Mine4", "Tile", "Tile3" }; - for (String name : names) { - URL file = Tile.class.getResource(name + ".ico"); - try { - icons.put(name, ImageIO.read(file)); - } catch (IOException e) { - System.err.println("Error loading texture: " + name); - e.printStackTrace(); - } - } - } - public Tile() { mine = flagged = touched = drawSurroundingMines = false;