john01dav
john01dav

Reputation: 1962

How to Render a Hex Grid

I am currently working on a game that requires a hexagon grid to be rendered in order to provide a place for the game to take place. I am using offset coordinates to store the hex grid in memory. When I attempt to render the grid, I get a result like the following with space between the hexes. I want the hexes to perfectly align so that all of the neccessary are at the exact same points, and so that their lines overlap and there is no space between the hexes

The coordinates inside each hex represent the offset coordinates of the hex. hex grid with extra space between the hexes

I am using the distances shown in the following image (source) to decide where to render each hex. hex grid with background rectangular grid showing distance between the centers of pointy-topped hexes

The only StackExchange question I was able to find that addresses a problem that sounds like this one is here. It, however, only talks about a data structure to store the hexes in and not how to render them from said structure. I am attempting to render them as described here, however, I get the buggy result shown above.

Here is the portion of my code that handles rendering (it should be easy to infer what the various custom methods do, if there is any confusion please let me know):

    @Override
public void paint(Graphics g){
    int quarterHexSize = 32; //using non static final member variables because I want to make this dynamically determine the largest size of the hexagons that will fit on the screen later
    int halfHexSize = quarterHexSize * 2;
    int hexSize = halfHexSize * 2;
    int cx, cy, renderX, renderY;

    g.setColor(Color.DARK_GRAY);
    g.fillRect(0, 0, getWidth(), getHeight());

    g.setColor(Color.WHITE);
    for(cx=0;cx<5;cx++){
        for(cy=0;cy<5;cy++){
            Hex hex = board.getHexAt(cx, cy);

            if(hex != null){
                renderX = cx * 2; //multiplying by 2 rather than using floats to represent half offset to simplify code and because IIRC integers are faster, I got the same error when using floats
                renderY = cy * 2;

                if(renderY % 4 != 0){
                    renderX++;
                }

                //converts the somewhat arbitrary units into the actual display size units using the values from the image in the question
                renderX *= hexSize;
                renderY *= quarterHexSize * 3f;

                //the numbers are divided by 2 to make up for the offset
                renderX /= 2;
                renderY /= 2;

                //64 is added to both dimensions to shift the grid inside the window
                renderX += 64;
                renderY += 64;

                drawHex(new RenderPoint(renderX, renderY), halfHexSize, g);
                g.drawString(cx + ", " + cy, renderX, renderY);
            }
        }
    }
}

private void drawHex(RenderPoint center, int hexSize, Graphics g){
    drawHexLine(center, hexSize, 0, 1, g);
    drawHexLine(center, hexSize, 1, 2,  g);
    drawHexLine(center, hexSize, 2, 3,  g);
    drawHexLine(center, hexSize, 3, 4,  g);
    drawHexLine(center, hexSize, 4, 5,  g);
    drawHexLine(center, hexSize, 5, 0,  g);
}

private void drawHexLine(RenderPoint center, int hexSize, int firstCornerNum, int secondCornerNum, Graphics g){
    RenderPoint firstCornerNumHexPoint = getHexCorner(center, hexSize, firstCornerNum);
    RenderPoint secondCornerNumHexPoint = getHexCorner(center, hexSize, secondCornerNum);

    g.drawLine(
            firstCornerNumHexPoint.getX(), firstCornerNumHexPoint.getY(),
            secondCornerNumHexPoint.getX(), secondCornerNumHexPoint.getY()
    );

    //g.drawString(String.valueOf(firstCornerNum), firstCornerNumHexPoint.getX(), firstCornerNumHexPoint.getY());
}

private RenderPoint getHexCorner(RenderPoint center, int hexSize, int cornerNum){
    return RenderPoint.doublesToInts( //simply rounds the provided doubles and creates a RenderPoint object with these new rounded values
            center.getX() + hexSize * Math.sin(cornerNum * 60 * 0.0174533), //decimal number converts from degrees to radians
            center.getY() + hexSize * Math.cos(cornerNum * 60 * 0.0174533)
    );
}

Upvotes: 2

Views: 2895

Answers (1)

john01dav
john01dav

Reputation: 1962

I have determined what the error was. I had missed a specific detail in the webpage when I assumed that the diagram I posted in the question completely explained the placement of the hexagons.

I have changed the variable renderX to:

renderX *= Math.round(HALF_SQRT_THREE * hexSize);

HALF_SQRT_THREE is a constant I defined in the variable to avoid recalculating it each time a hexagon is rendered. It is defined as Math.sqrt(3)/2.0.

Here is the quote from the webpage:

The width of a hexagon is width = sqrt(3)/2 * height. The horizontal distance between adjacent hexes is horiz = width.

Upvotes: 1

Related Questions