Как заставить JPanel перерисовывать с помощью анимации? - PullRequest
0 голосов
/ 26 сентября 2019

Я создаю инструмент, который будет генерировать лабиринт, используя рекурсивный бэктрекер.Программа успешно создает лабиринт, но я хочу, чтобы процесс был анимирован (аналогично тому, как это показано здесь ).

Я пытался использовать многопоточность, как мне советовали,но я не уверен, что действительно понимаю, как это сделать, поскольку то, что я пытался, похоже, не работает.

Вот JButton, который запускает создание лабиринта:

JButton genMaze = new JButton("Generate new maze");
        genMaze.setAlignmentX(JButton.CENTER_ALIGNMENT);
        genMaze.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ((DepthFirst) animation).resetAnimation();
                ((DepthFirst) animation).startTimer();
                ((DepthFirst) animation).run();               
            }
        });

Вот класс DepthFirst:

public class DepthFirst extends Maze implements Runnable {

    DepthFirst() {
        super.initMaze();
    }

    public void run() {
        depthFirstGeneration(Maze.startX, Maze.startY);
    }

    public void startGen() {
        depthFirstGeneration(super.startX, super.startY);
    }

    public void depthFirstGeneration(int x, int y) { // up = 1, right = 2, down = 3, left = 4
        super.cell[x][y] = Mark.CURRENT;
        this.repaint();
        this.revalidate();
        /*try {
            Thread.sleep(10);
        } catch (Exception e) {
            System.out.println(e);
        }*/
        Dir[] directions = getDirections();
        for (int i = 0; i < directions.length; i++) {

            switch (directions[i]) {
                case UP: // up
                    if (y - 2 <= 0) // check if going up would go outside of the maze
                        continue;
                    if (super.cell[x][y - 2] == Mark.WALL) { // check that the space is available
                        super.cell[x][y] = Mark.PATH; // sets 'current' cell to no longer be current
                        super.cell[x][y - 1] = Mark.PATH; // sets the spaces ahead to a path
                        super.cell[x][y - 2] = Mark.PATH;
                        depthFirstGeneration(x, y - 2); // call the same subroutine using the new coordinates
                    }
                    break;
                case DOWN: // down
                    if (y + 2 >= mazeSize)
                        continue;
                    if (super.cell[x][y + 2] == Mark.WALL) {
                        super.cell[x][y] = Mark.PATH;
                        super.cell[x][y + 1] = Mark.PATH;
                        super.cell[x][y + 2] = Mark.PATH;
                        depthFirstGeneration(x, y + 2);
                    }
                    break;
                case LEFT: // left
                    if (x - 2 <= 0)
                        continue;
                    if (super.cell[x - 2][y] == Mark.WALL) {
                        super.cell[x][y] = Mark.PATH;
                        super.cell[x - 1][y] = Mark.PATH;
                        super.cell[x - 2][y] = Mark.PATH;
                        depthFirstGeneration(x - 2, y);
                    }
                    break;
                case RIGHT: // right
                    if (x + 2 >= mazeSize)
                        continue;
                    if (super.cell[x + 2][y] == Mark.WALL) {
                        super.cell[x][y] = Mark.PATH;
                        super.cell[x + 1][y] = Mark.PATH;
                        super.cell[x + 2][y] = Mark.PATH;
                        depthFirstGeneration(x + 2, y);
                    }
                    break;
            }
        }        
    }

    public Dir[] getDirections() {
        Dir[] directions = {Dir.UP, Dir.DOWN, Dir.LEFT, Dir.RIGHT};
        Dir[] shuffle = new Dir[4];
        for (int i = 0; i < directions.length; i++) {
            int rand = super.random.nextInt(directions.length);
            while (directions[rand] == Dir.NULL) {
                rand = super.random.nextInt(directions.length);
            }
            Dir temp = directions[rand];
            directions[rand] = Dir.NULL;
            shuffle[i] = temp;
        }
        return shuffle;
    }

}

Вот класс Maze:

public abstract class Maze extends JPanel implements ActionListener {

    public static final int mazeSize = 35;
    volatile static Random random = new Random();
    public Timer tm = new Timer(50, this);
    volatile static Mark[][] cell = new Mark[mazeSize][mazeSize];
    volatile int x = 0, y = 0;
    volatile static int startX = 1, startY = 1, endX = mazeSize - 1, endY = mazeSize - 1;
    Color bg;

    Maze() {
        bg = this.getBackground();
        this.setBackground(Color.DARK_GRAY);
    }

    public void startTimer() {
        tm.restart();
    }

    public void resetAnimation() {
        for (int i = 0; i < mazeSize; i++){
            for (int j = 0; j < mazeSize; j++){
                cell[i][j] = Mark.WALL;
            }
        }
        repaint();
        x = 0; y = 0;
    }

    public void initMaze(){
        for(int i = 0; i < mazeSize; i++){
            for(int j = 0; j < mazeSize; j++){
                cell[i][j] = Mark.WALL;
            }
        }

    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(bg);
        g.fillRect(20, 0, 10, 20); // start square
        g.fillRect(mazeSize * 10 - 10, mazeSize * 10 + 10, 10, 10); //
        cell[1][0] = Mark.PATH;
        cell[mazeSize - 2][mazeSize - 1] = Mark.PATH;
        for (int yy = 0; yy < mazeSize; yy++) {
            for (int xx = 0; xx < mazeSize; xx++) {
                if (cell[xx][yy] == Mark.WALL){
                    g.setColor(Color.DARK_GRAY);
                    g.fillRect(xx * 10 + 10, yy * 10 + 10, 10, 10);
                } else if (cell[xx][yy] == Mark.PATH) {
                    g.setColor(bg);
                    g.fillRect(xx * 10 + 10, yy * 10 + 10, 10, 10);
                } else if (cell[xx][yy] == Mark.CURRENT) {
                    g.setColor(Color.RED);
                    g.fillRect(xx * 10 + 10, yy * 10 + 10, 10, 10);
                }
            }
        }
    }

    public void actionPerformed(ActionEvent e) {
        repaint();
    }

}

Я ожидал, что панель будет перекрашиваться каждый раз, когда отмечается пара ячеек, нопрограмма отображает весь (завершенный) лабиринт одновременно.

Я не уверен, что мне следует делать, чтобы это исправить.

...