javafxhexagonal-tiles

Create hexagonal field with JavaFX


I have the goal to create a field of hexagonal tiles. I have come as far as having a matrix of cells, each high enough to fit the complete hexagon image:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class UITest extends Application {
    final private static String TILE_IMAGE_LOCATION = System.getProperty("user.dir") + File.separatorChar +"resources"+ File.separatorChar + "blueTile.png";
    final private static Image HEXAGON_IMAGE = initTileImage();

    private static Image initTileImage() {
        try {
            return new Image(new FileInputStream(new File(TILE_IMAGE_LOCATION)));
        } catch (FileNotFoundException e) {
            throw new IllegalStateException(e);
        }
    }
    public void start(Stage primaryStage) {
        int height = 4;
        int width = 6;
        GridPane tileMap = new GridPane();
        Scene content = new Scene(tileMap, 800, 600);
        primaryStage.setScene(content);

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                ImageView tile = new ImageView(HEXAGON_IMAGE);
                GridPane.setConstraints(tile, x, y);
                tileMap.getChildren().add(tile);
            }
        }

        primaryStage.show();
    }
}

My problem is not the vertical gap, which I can surely figure out by adding the GridPane's vGap() to a proper value. The difficulty for me is shifting each second row half a cellwidth to the right.

I have attempted to lay two GridPanes over eachother, one containing the odd and one the even rows, with the goal to add padding to one of them, shifting it entirely. To my knowledge however, there is no way for this, as well as nesting GridPanes into on another.

How can I best achieve the shifting of only every second row?

(The image I reference in the code which is expected in the ${projectroot}/resources/ folder: blue hexagon tile )


Solution

  • It took me some time to figure it out. I hope it helps. I don't use an image. It's made of polygons, you can customize the stroke and fill color, as well as the width.

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.paint.Paint;
    import javafx.scene.shape.Polygon;
    
    public class UITest extends Application {
        public void start(Stage primaryStage) {
            int height = 600;
            int width = 800;
            AnchorPane tileMap = new AnchorPane();
            Scene content = new Scene(tileMap, width, height);
            primaryStage.setScene(content);
            double size = 50,v=Math.sqrt(3)/2.0;
            for(double y=0;y<height;y+=size*Math.sqrt(3))
            {
                for(double x=-25,dy=y;x<width;x+=(3.0/2.0)*size)
                {
                    Polygon tile = new Polygon();
                    tile.getPoints().addAll(new Double[]{
                        x,dy,
                        x+size,dy,
                        x+size*(3.0/2.0),dy+size*v,
                        x+size,dy+size*Math.sqrt(3),
                        x,dy+size*Math.sqrt(3),
                        x-(size/2.0),dy+size*v
                    });
                    tile.setFill(Paint.valueOf("#ffffff"));
                    tile.setStrokeWidth(2);
                    tile.setStroke(Paint.valueOf("#000000") );
                    tileMap.getChildren().add(tile);
                    dy = dy==y ? dy+size*v : y;
                }
            }
            primaryStage.show();
        }
        public static void main(String[] args)
        {
            launch(args);
        }
    }