4

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 )

Dennis
  • 1,061
  • 10
  • 21

2 Answers2

7

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);
    }
}
Cthulhu
  • 699
  • 1
  • 10
  • 21
3

For other interested souls out there, I have used the accepted answer by Cthulhu and improved/documented the given code as a short standalone demonstration:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;

public class UISolution extends Application {

    private final static int WINDOW_WIDTH = 800;
    private final static int WINDOW_HEIGHT = 600;

    private final static double r = 20; // the inner radius from hexagon center to outer corner
    private final static double n = Math.sqrt(r * r * 0.75); // the inner radius from hexagon center to middle of the axis
    private final static double TILE_HEIGHT = 2 * r;
    private final static double TILE_WIDTH = 2 * n;

    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage primaryStage) {
        AnchorPane tileMap = new AnchorPane();
        Scene content = new Scene(tileMap, WINDOW_WIDTH, WINDOW_HEIGHT);
        primaryStage.setScene(content);

        int rowCount = 4; // how many rows of tiles should be created
        int tilesPerRow = 6; // the amount of tiles that are contained in each row
        int xStartOffset = 40; // offsets the entire field to the right
        int yStartOffset = 40; // offsets the entire fiels downwards

        for (int x = 0; x < tilesPerRow; x++) {
            for (int y = 0; y < rowCount; y++) {
                double xCoord = x * TILE_WIDTH + (y % 2) * n + xStartOffset;
                double yCoord = y * TILE_HEIGHT * 0.75 + yStartOffset;

                Polygon tile = new Tile(xCoord, yCoord);
                tileMap.getChildren().add(tile);
            }
        }
        primaryStage.show();
    }

    private class Tile extends Polygon {
        Tile(double x, double y) {
            // creates the polygon using the corner coordinates
            getPoints().addAll(
                    x, y,
                    x, y + r,
                    x + n, y + r * 1.5,
                    x + TILE_WIDTH, y + r,
                    x + TILE_WIDTH, y,
                    x + n, y - r * 0.5
            );

            // set up the visuals and a click listener for the tile
            setFill(Color.ANTIQUEWHITE);
            setStrokeWidth(1);
            setStroke(Color.BLACK);
            setOnMouseClicked(e -> System.out.println("Clicked: " + this));
        }
    }
}
Dennis
  • 1,061
  • 10
  • 21