How to Fix Flickering JFrame in Java Minesweeper?

  • Java
  • Thread starter Kaura
  • Start date
  • Tags
    java
  • #1
Kaura
122
22
Hello, I am currently working on a version of Minesweeper that uses Java.
Currently the code seems to work relatively well and the game runs properly, however there is an issue.
I currently have the set to update the board on every mouse click and release, as these are currently the only actions that can trigger a change in the board. I have not implemented a timer yet. The board updates correctly but it flickers, flashing white for a moment and then quickly drawing the objects on the board like the tiles.
I believe that this is due to me using a loop in the paint method to individually draw each tile based on its given characteristics. I do not know if this is simply too much for the system to handle when trying to drawing instantaneously or if there is some other underlying issue.
I have searched the web and I think that implementing double buffering or what not might solve the issue but I am not exactly sure how to do that.
Here is the code, any advice is much appreciated.

Java:
//================================//

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import java.awt.Font;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Scanner;

/********
 * Minesweeper
 * @author Kaura
 ********/
public class Minesweeper {
  
    /****
    * Tile
    ****/
    public static class Tile {
      
        private boolean bomb = false;
        private boolean marked = false;
        private boolean covered = true;
        private int number = 0;
      
        public boolean checkBomb() {return bomb;}
        public boolean checkMarked() {return marked;}
        public boolean checkCovered() {return covered;}
        public int getNumber() {return number;}
        public void setBomb() {bomb = true;}
        public void mark() {marked = !marked;}
        public void uncover() {covered = false;}
        public void setNumber(int number) {this.number = number;}
      
    }
  
    /****
    * Board
    ****/
    public static class Board {
      
        private int width;
        private int height;
        private int difficulty;
        private int bombs;
        private int covered;
        private int marked;
        private int deadX;
        private int deadY;
        private long time;
        private boolean running;
        private boolean winner;
        private Tile[][] tiles;
      
        public Board(int width, int height, int bombs) {
          
            this.width = width;
            this.height = height;
            this.bombs = bombs;
            this.covered = width*height;
            this.marked = 0;
            this.deadX = -1;
            this.deadY = -1;
            this.time = System.currentTimeMillis();
            this.running = true;
            this.winner = false;
          
            //Create Tiles//
            tiles = new Tile[width][height];
            for(int k = 0; k < width; k++) {
                for(int f = 0; f < height; f++) {
                    tiles[k][f] = new Tile();
                }
            }
          
            //Set Bombs//
            for(int k = 0; k < bombs; k++) {
                int x = (int)Math.floor(Math.random()*width);
                int y = (int)Math.floor(Math.random()*height);
                if(!tiles[x][y].checkBomb()) {
                    tiles[x][y].setBomb();
                } else {
                    k--;
                }
            }
          
            //Set Numbers//
            for(int k = 0; k < width; k++) {
                for(int f = 0; f < height; f++) {
                    int total = 0;
                    if(k > 0 && f > 0 && tiles[k-1][f-1].checkBomb()) total++;
                    if(f > 0 && tiles[k][f-1].checkBomb()) total++;
                    if(k < width-1 && f > 0 && tiles[k+1][f-1].checkBomb()) total++;
                    if(k > 0 && tiles[k-1][f].checkBomb()) total++;
                    if(k < width-1 && tiles[k+1][f].checkBomb()) total++;
                    if(k > 0 && f < height-1 && tiles[k-1][f+1].checkBomb()) total++;
                    if(f < height-1 && tiles[k][f+1].checkBomb()) total++;
                    if(k < width-1 && f < height-1 && tiles[k+1][f+1].checkBomb()) total++;
                    tiles[k][f].setNumber(total);
                }
            }
        }
      
        //Uncover a Tile//
        public void uncoverTile(int x, int y) {
            covered--;
            tiles[x][y].uncover();
            if(tiles[x][y].checkMarked()) markTile(x, y);
            if(tiles[x][y].checkBomb()) {
                deadX = x;
                deadY = y;
                gameover();
                return;
            } else if(tiles[x][y].getNumber() == 0) {
                for(int k = (x==0?0:-1); k <= (x<width-1?1:0); k++) {
                    for(int f = (y==0?0:-1); f <= (y<height-1?1:0); f++) {
                        if(tiles[k+x][f+y].checkCovered()) {
                            uncoverTile((k+x), (f+y));
                        }
                    }
                }      
            } if(covered <= bombs) {
                winner = true;
                gameover();
            }
        }
      
        //Mark Tile//
        public void markTile(int x, int y) {
            if(!tiles[x][y].checkCovered()) return;
            tiles[x][y].mark();
            marked += (tiles[x][y].checkMarked())?1:-1;
        }
      
        //Uncover Bombs//
        public void reveal() {
            for(int k = 0; k < this.width; k++) {
                for(int f = 0; f < this.height; f++) {
                    if(tiles[k][f].checkBomb()) tiles[k][f].uncover();
                }
            }
        }
      
        //Game Over//
        public void gameover() {
            running = false;
            if(!winner) reveal();
            System.out.print("Game Over: ");
            System.out.println((winner)?"You Win":"You Lose");
        }
      
        //Timer//
        public int getTime() {
            return (int)(System.currentTimeMillis()-time)/1000;
        }
      
        //Access//
        public int getWidth() {return this.width;}
        public int getHeight() {return this.height;}
        public int getBombs() {return this.bombs;}
        public int getCovered() {return this.covered;}
        public int getMarked() {return this.marked;}
        public int getDeadX() {return this.deadX;}
        public int getDeadY() {return this.deadY;}
        public boolean checkRunning() {return this.running;}
        public Tile getTile(int x, int y) {return this.tiles[x][y];}
      
    }
  
    /****
    * Screen
    ****/
    public static class Screen extends JFrame implements MouseListener {
      
        private static final long serialVersionUID = 1L;
      
        private final int WIDTH = 960;
        private final int HEIGHT = 960;
        private final int TILE = 40;
      
        private final Font font = new Font("Terminal", Font.BOLD, 30);
      
        private final Color BG = Color.decode("#black");
        private final Color FG = Color.decode("#f0f0f0");
        private final Color GD = Color.decode("#c0c0c0");
        private final Color HL1 = Color.decode("#f8f8f8");
        private final Color HL2 = Color.decode("#c0c0c0");
        private final Color F1 = Color.decode("#000000");
        private final Color F2 = Color.decode("#ff0000");
        private final Color BM = Color.decode("#000000");
        private final Color EX = Color.decode("#ff0000");
      
        private final Color[] color = {
            Color.decode("#f0f0f0"),
            Color.decode("#0100fe"),
            Color.decode("#017f01"),
            Color.decode("#fe0000"),
            Color.decode("#010080"),
            Color.decode("#0100fe"),
            Color.decode("#810102"),
            Color.decode("#008081"),
            Color.decode("#000000"),
            Color.decode("#808080"),
        };
      
        private int boardX, boardY;
        private int boardWidth, boardHeight;
      
        private Board board;
      
        //Constructor//
        public Screen() {
            addMouseListener(this);
            setTitle("Minesweeper");
            setSize(WIDTH, HEIGHT);
            setResizable(false);
            setVisible(true);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            newgame();
        }
      
        //New Game//
        private void newgame() {
            board = new Board(20, 15, 25);
            boardX = WIDTH/2-board.getWidth()*TILE/2;
            boardY = HEIGHT/2-board.getHeight()*TILE/2;
            boardWidth = board.getWidth()*TILE;
            boardHeight = board.getHeight()*TILE;
        }
      
        //Painter//
        public void paint(Graphics canvas) {
            canvas.clearRect(0, 0, WIDTH, HEIGHT);
          
            canvas.setColor(BG);
            canvas.fillRect(0, 0, WIDTH, HEIGHT);
          
            canvas.setColor(HL2);
            canvas.fillPolygon(
                new int[] {boardX-6, boardX+boardWidth+6, boardX-6},
                new int[] {boardY-6, boardY-6, boardY+boardHeight+6}, 3
            );
          
            canvas.setColor(HL1);
            canvas.fillPolygon(
                new int[] {boardX+boardWidth+6, boardX-6, boardX+boardWidth+6},
                new int[] {boardY+boardHeight+6, boardY+boardHeight+6, boardY-6}, 3
            );
          
            canvas.setColor(FG);
            canvas.fillRect(boardX, boardY, boardWidth, boardHeight);
          
            canvas.setColor(GD);
            for(int k = 0; k < board.getWidth(); k++) {
                canvas.drawLine(boardX+k*TILE, boardY, boardX+k*TILE, boardY+boardHeight);
            } for(int k = 0; k < board.getHeight(); k++) {
                canvas.drawLine(boardX, boardY+k*TILE, boardX+boardWidth, boardY+k*TILE);
            }
          
            //Fill Board//
            for(int k = 0; k < board.getWidth(); k++) {
                for(int f = 0; f < board.getHeight(); f++) {
                  
                    //Base//
                    if(board.getTile(k, f).checkBomb()) {
                        if(k == board.getDeadX() && f == board.getDeadY()) {
                            canvas.setColor(EX);
                            canvas.fillRect(boardX+k*TILE, boardY+f*TILE, TILE, TILE);
                        }
                        canvas.setColor(BM);
                        canvas.fillOval(boardX+k*TILE+TILE/2-9, boardY+f*TILE+TILE/2-9, 20, 20);
                        canvas.setColor(FG);
                        canvas.fillOval(boardX+k*TILE+TILE/2-5, boardY+f*TILE+TILE/2-5, 6, 6);
                    } else {
                        canvas.setFont(font);
                        canvas.setColor(color[board.getTile(k, f).getNumber()]);
                        canvas.drawString(board.getTile(k, f).getNumber()+"", boardX+k*TILE+TILE/2-7, boardY+f*TILE+TILE/2+12);
                    }
                  
                    //Covered
                    if(board.getTile(k, f).checkCovered()) {
                        canvas.setColor(HL1);
                        canvas.fillPolygon(
                            new int[] {boardX+k*TILE, boardX+k*TILE+TILE, boardX+k*TILE},
                            new int[] {boardY+f*TILE, boardY+f*TILE, boardY+f*TILE+TILE}, 3
                        );
                        canvas.setColor(HL2);
                        canvas.fillPolygon(
                            new int[] {boardX+k*TILE, boardX+k*TILE+TILE, boardX+k*TILE+TILE},
                            new int[] {boardY+f*TILE+TILE, boardY+f*TILE+TILE, boardY+f*TILE}, 3
                        );
                        canvas.setColor(BG);
                        canvas.fillRect(boardX+k*TILE+5, boardY+f*TILE+5, 30, 30);
                    }
                  
                    //Marked//
                    if(board.getTile(k, f).checkMarked()) {
                        canvas.setColor(F1);
                        canvas.fillPolygon(
                            new int[] {
                                boardX+k*TILE+10, boardX+k*TILE+10,
                                boardX+k*TILE+19, boardX+k*TILE+19,
                                boardX+k*TILE+21, boardX+k*TILE+21,
                                boardX+k*TILE+30, boardX+k*TILE+30
                            },
                            new int[] {
                                boardY+f*TILE+32, boardY+f*TILE+26,
                                boardY+f*TILE+24, boardY+f*TILE+8,
                                boardY+f*TILE+8, boardY+f*TILE+24,
                                boardY+f*TILE+26, boardY+f*TILE+32
                            }, 8
                        );
                        canvas.setColor(F2);
                        canvas.fillPolygon(
                            new int[] {boardX+k*TILE+21, boardX+k*TILE+10, boardX+k*TILE+10, boardX+k*TILE+21},
                            new int[] {boardY+f*TILE+6, boardY+f*TILE+12, boardY+f*TILE+14, boardY+f*TILE+20}, 4
                        );
                    }
                }
            }

        }
      
        //Mouse Events//
        private int pressX, pressY, releaseX, releaseY;
        public void mouseClicked(MouseEvent e) {return;}
        public void mouseEntered(MouseEvent e) {return;}
        public void mouseExited(MouseEvent e) {return;}
      
        public void mousePressed(MouseEvent e) {
            if(board.checkRunning()) {
              pressX = e.getX();
                pressY = e.getY();
                int tileX = (pressX-boardX)/TILE;
                int tileY = (pressY-boardY)/TILE;
            } repaint();
        }
      
        public void mouseReleased(MouseEvent e) {
            if(board.checkRunning()) {
                releaseX = e.getX();
                releaseY = e.getY();
                int tileX = (releaseX-boardX)/TILE;
                int tileY = (releaseY-boardY)/TILE;
                if(tileX != (pressX-boardX)/TILE || tileY != (pressY-boardY)/TILE) return;
                if((tileX<0||tileX>board.getWidth())||(tileY<0||tileY>board.getHeight())) return;
  
                //System.out.println(tileX+", "+tileY);
                Tile tile = board.getTile(tileX, tileY);
              
                if(SwingUtilities.isLeftMouseButton(e)) {
                    if(!tile.checkMarked()) {
                        if(tile.checkCovered()) {
                            board.uncoverTile(tileX, tileY);
                        }
                    }
                } else if(SwingUtilities.isRightMouseButton(e)) {
                    board.markTile(tileX, tileY);
                }
            } repaint();
        }
      
    }

    /****
    * Main Method
    ****/
    public static void main(String[] args) {
      
        Screen game = new Screen();
      
    }

}

//================================//
 
Last edited by a moderator:
Technology news on Phys.org

Similar threads

Replies
1
Views
3K
Replies
6
Views
2K
Replies
5
Views
2K
Replies
2
Views
2K
Replies
1
Views
2K
Replies
3
Views
3K
Replies
5
Views
2K
Back
Top