Reputation: 798
I have some code in a MazeUI class that creates a couple of fields in JavaFX for entering the height and width of a Maze to be generated along with a Button and the event for the button. On clicking Generate Maze the code should generate a random maze.
Now this works fine. But the line to clear the canvas after the Maze is first drawn using gc.clearRect(x, y, z, a) doesn't appear to work and Maze's are re-drawn on top of one another on subsequent clicks:
package dojo.maze.ui;
import dojo.maze.generator.MazeGenerator;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.effect.BoxBlur;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.stage.Stage;
public class MazeUI extends Application {
private MazeGenerator generator;
private Integer height = 15;
private Integer width = 15;
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Dojo: Solving a Maze");
Group root = new Group();
drawMazeView(root);
primaryStage.setScene(new Scene(root, Color.WHITE));
primaryStage.show();
}
private GraphicsContext initialiseGraphicsContext(Canvas canvas) {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.BLACK);
gc.fillRect(0,0,600,600);
gc.setStroke(Color.GREEN);
gc.setLineCap( StrokeLineCap.ROUND );
gc.setLineJoin( StrokeLineJoin.ROUND );
gc.setLineWidth(3);
BoxBlur blur = new BoxBlur();
blur.setWidth(1);
blur.setHeight(1);
blur.setIterations(1);
gc.setEffect(blur);
return gc;
}
private void drawMazeView(Group root) {
Canvas canvas = new Canvas(800, 800);
GraphicsContext gc = initialiseGraphicsContext(canvas);
GridPane.setConstraints(canvas, 0, 6);
GridPane grid = new GridPane();
grid.setPadding(new Insets(10, 10, 10, 10));
grid.setVgap(5);
grid.setHgap(5);
Label heightLabel = new Label("Height:");
final TextField heightTextField = new TextField();
HBox hbHeight = new HBox();
hbHeight.getChildren().addAll(heightLabel, heightTextField);
hbHeight.setSpacing(10);
GridPane.setConstraints(hbHeight, 0, 0);
Label widthLabel = new Label("Label:");
final TextField widthTextField = new TextField();
HBox hbWidth = new HBox();
hbWidth.getChildren().addAll(widthLabel, widthTextField);
hbWidth.setSpacing(10);
GridPane.setConstraints(hbWidth, 0, 2);
VBox fieldsBox = new VBox();
fieldsBox.getChildren().addAll(hbHeight, hbWidth);
// Create button that allows you to generate a new maze
Button btn = new Button();
btn.setText("Generate Random Maze");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Button clicked!");
height = Integer.valueOf(heightTextField.getText());
width = Integer.valueOf(widthTextField.getText());
// clear old maze
gc.clearRect(0, 0,
canvas.getHeight(),
canvas.getWidth());
generator = new MazeGenerator(height, width);
drawMaze(gc);
}
});
GridPane.setConstraints(btn, 0, 4);
grid.getChildren().addAll(fieldsBox, btn, canvas);
root.getChildren().add(grid);
}
void drawMaze(GraphicsContext gc) {
int[][] maze = generator.maze();
int xPos = 20,
yPos = 20,
length = 40,
gap = 10;
for (int i = 0; i < width; i++) {
xPos = 20;
// draw the north edge
for (int j = 0; j < height; j++) {
if ((maze[j][i] & 1) == 0) {
gc.strokeLine(xPos, yPos, xPos + length, yPos); // horizontal
}
xPos += length + gap;
System.out.print((maze[j][i] & 1) == 0 ? "+---" : "+ ");
}
System.out.println("+");
xPos = 20;
// draw the west edge
for (int j = 0; j < height; j++) {
if ((maze[j][i] & 8) == 0) {
gc.strokeLine(xPos, yPos, xPos, yPos + length); // vertical
}
xPos += length + gap;
System.out.print((maze[j][i] & 8) == 0 ? "| " : " ");
}
gc.strokeLine(xPos, yPos, xPos, yPos + length); // vertical
System.out.println("|");
yPos += length + gap;
}
// draw the bottom line
xPos = 20; // reset x pos to western edge
for (int j = 0; j < height; j++) {
gc.strokeLine(xPos, yPos, xPos + length, yPos); // horizontal
System.out.print("+---");
xPos += length + gap;
}
System.out.println("+");
}
public static void main(String[] args) {
launch(args);
}
}
Code for MazeGenerator:
package dojo.maze.generator;
import java.util.Arrays;
import java.util.Collections;
/*
* recursive backtracking algorithm
* shamelessly borrowed from the ruby at
* http://weblog.jamisbuck.org/2010/12/27/maze-generation-recursive-backtracking
*/
public class MazeGenerator {
private final int x;
private final int y;
private final int[][] maze;
public static final int[][] mazeProblemOne = new int[][] {{2,5,2,3,7,3,1,6,7,3,3,5,6,3,5},{4,10,3,5,12,6,3,9,10,3,5,12,8,6,13},{12,6,5,12,12,14,3,1,6,3,9,10,3,9,12},{12,12,12,12,12,12,6,3,9,4,6,7,1,6,9},{14,9,10,9,12,12,12,6,5,12,12,10,5,12,4},{12,2,7,5,12,12,10,9,12,10,13,4,10,9,12},{12,6,9,12,12,12,2,5,10,5,10,11,3,3,13},{12,10,5,12,10,11,3,13,4,10,5,6,3,1,12},{12,6,9,10,5,4,6,9,12,6,9,12,6,3,9},{10,9,6,1,12,10,11,3,9,12,6,13,12,2,5},{6,7,9,6,9,6,3,3,3,9,8,12,12,6,13},{8,12,6,9,6,13,6,3,7,3,3,13,12,12,12},{6,9,10,5,12,12,12,4,10,3,5,8,12,12,8},{14,3,5,12,8,12,10,11,3,5,10,5,12,10,5},{10,1,10,11,3,9,2,3,3,11,1,10,11,3,9}};
public static final int[][] mazeProblemTwo = new int[][] {{2,5,6,5,6,3,1,6,3,3,7,5,2,3,5},{4,10,9,12,14,3,3,9,6,5,12,10,3,3,9},{14,3,3,9,8,6,3,5,12,12,10,3,3,3,5},{12,6,3,3,5,12,4,10,9,10,3,3,3,3,13},{12,12,6,5,12,12,10,3,3,3,5,6,3,3,9},{12,10,9,12,10,9,6,5,6,3,13,10,3,3,5},{10,3,5,12,6,5,12,10,9,4,14,3,3,1,12},{4,6,9,12,12,10,9,6,3,11,13,6,3,3,9},{12,12,2,13,14,3,5,8,6,5,8,10,3,3,5},{12,10,3,9,12,4,12,6,9,12,6,5,6,3,9},{14,7,3,1,10,13,12,12,4,12,12,10,9,6,1},{12,10,3,7,1,12,10,11,9,12,12,2,3,11,5},{12,2,5,12,6,9,2,5,6,9,10,3,3,5,12},{10,5,12,12,12,6,3,13,12,6,7,1,6,9,12},{2,11,9,10,11,9,2,9,10,9,10,3,11,3,9}};
public static final int[][] mazeProblemThree = new int[][] {{2,5,2,3,7,3,3,3,5,6,3,1,6,7,1},{4,10,3,5,12,2,5,6,9,10,3,3,9,14,5},{10,7,5,12,10,5,14,9,6,5,6,3,5,12,12},{6,9,8,10,3,9,12,6,13,12,10,5,12,12,12},{12,6,3,7,1,6,9,12,12,10,3,9,12,8,12},{12,12,4,10,5,10,5,8,14,3,5,2,11,3,13},{12,10,13,4,10,5,10,5,10,5,10,5,6,5,12},{14,1,12,10,5,14,1,12,6,9,4,10,9,12,12},{14,5,10,5,12,10,5,12,12,2,15,3,1,12,12},{8,12,6,9,10,5,12,12,10,3,9,6,3,9,12},{6,9,14,3,3,9,12,10,3,3,3,9,4,6,9},{10,5,12,6,3,3,13,6,3,3,1,6,11,9,4},{6,9,12,10,5,6,11,9,6,3,3,9,6,3,13},{14,5,12,4,12,10,1,6,9,6,5,2,13,4,12},{8,10,11,9,10,3,3,11,3,9,10,3,9,10,9}};
public static final int[][] mazeProblemFour = new int[][] {{2,3,3,5,4,6,7,3,3,5,6,5,6,3,5},{6,3,1,12,12,12,10,3,5,10,9,12,10,5,12},{12,6,3,9,14,9,4,6,9,2,3,11,1,12,12},{14,9,2,3,11,5,12,10,3,5,6,3,3,9,12},{10,5,6,5,2,11,11,5,4,12,12,6,7,1,12},{4,10,9,10,3,5,6,9,12,10,9,8,12,6,13},{14,5,4,6,3,9,12,6,11,5,6,3,9,12,8},{12,10,9,12,4,6,9,10,5,12,14,3,5,10,5},{12,6,5,12,12,12,6,3,9,12,8,6,13,4,12},{14,9,10,9,12,12,10,3,5,10,5,12,10,13,12},{12,2,7,5,10,11,3,3,9,6,9,12,2,9,12},{10,3,9,10,3,3,5,4,6,11,3,9,6,3,13},{6,5,6,7,3,5,12,10,9,6,3,3,9,6,9},{12,10,9,10,5,8,12,6,5,10,5,6,5,10,5},{10,3,3,1,10,3,11,9,10,3,9,8,10,3,9}};
public static final int[][] mazeProblemFive = new int[][] {{2,3,5,6,3,3,7,5,6,3,3,3,7,3,5},{6,5,12,12,6,3,9,8,10,5,4,6,9,4,12},{12,12,12,12,10,3,5,6,5,10,13,10,5,14,9},{12,10,9,10,5,4,10,9,14,1,12,4,12,10,5},{10,5,6,5,10,15,3,1,14,5,14,9,10,5,8},{6,9,12,10,5,8,6,5,8,10,9,6,5,14,5},{10,3,9,4,12,6,9,10,3,3,3,9,12,8,12},{6,3,7,13,12,10,7,5,2,7,7,1,10,3,13},{14,1,12,8,10,5,12,12,6,9,12,6,3,3,9},{8,6,13,6,3,9,12,12,12,2,13,12,6,3,5},{6,9,8,12,4,6,9,12,14,5,8,10,9,4,12},{12,6,3,9,10,9,6,9,8,10,7,5,6,11,9},{12,10,3,3,3,5,14,3,3,5,12,12,10,5,4},{14,1,6,5,6,9,10,3,1,12,12,10,1,10,13},{10,3,9,10,11,3,3,3,3,9,10,3,3,3,9}};
public MazeGenerator(int x, int y) {
this.x = x;
this.y = y;
maze = new int[this.x][this.y];
generateMaze(0, 0);
}
public void display() {
for (int i = 0; i < y; i++) {
// draw the bbc.north edge
for (int j = 0; j < x; j++) {
System.out.print((maze[j][i] & 1) == 0 ? "+---" : "+ ");
}
System.out.println("+");
// draw the west edge
for (int j = 0; j < x; j++) {
System.out.print((maze[j][i] & 8) == 0 ? "| " : " ");
}
System.out.println("|");
}
// draw the bottom line
for (int j = 0; j < x; j++) {
System.out.print("+---");
}
System.out.println("+");
}
private void generateMaze(int cx, int cy) {
DIR[] dirs = DIR.values();
Collections.shuffle(Arrays.asList(dirs));
for (DIR dir : dirs) {
int nx = cx + dir.dx;
int ny = cy + dir.dy;
if (between(nx, x) && between(ny, y)
&& (maze[nx][ny] == 0)) {
maze[cx][cy] |= dir.bit;
maze[nx][ny] |= dir.opposite.bit;
generateMaze(nx, ny);
}
}
}
private static boolean between(int v, int upper) {
return (v >= 0) && (v < upper);
}
public int[][] maze() {
return maze;
}
private enum DIR {
N(1, 0, -1), S(2, 0, 1), E(4, 1, 0), W(8, -1, 0);
private final int bit;
private final int dx;
private final int dy;
private DIR opposite;
// use the static initializer to resolve forward references
static {
N.opposite = S;
S.opposite = N;
E.opposite = W;
W.opposite = E;
}
private DIR(int bit, int dx, int dy) {
this.bit = bit;
this.dx = dx;
this.dy = dy;
}
};
public static void main(String[] args) {
int x = args.length >= 1 ? (Integer.parseInt(args[0])) : 8;
int y = args.length == 2 ? (Integer.parseInt(args[1])) : 8;
MazeGenerator maze = new MazeGenerator(x, y);
maze.display();
}
}
How do I fix the code so that it correctly clears the Maze after each button click? Am I missing something?
Upvotes: 1
Views: 1344
Reputation: 245
For people looking for an answer, another reason why it may not be working is if you set the GraphicsContext.globalBlendMode
to something like BlendMode.SCREEN
.
Since clearRect()
paints the canvas with transparent pixels, a transparent pixel would have no effect in that BlendMode.
Set the gc.globalBlendMode = BlendMode.SRC_OVER
right before calling clearRect()
Upvotes: 0
Reputation: 18415
Remove the BoxBlur effect before you clear the canvas, then re-apply it. Clearing the canvas simply paints with a transparent color. So the BoxBlur effect will affect that too.
And what jewelsea said. You'd have found it yourself if you'd only reduced the code to a minimum ;-)
Upvotes: 2