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