flauwekeul / honeycomb

Create hex grids easily, in node or the browser.
https://abbekeultjes.nl/honeycomb
MIT License
639 stars 59 forks source link

Pointy produces grid with gaps #114

Closed netgfx closed 8 months ago

netgfx commented 8 months ago

Describe the bug The screenshot shows what it looks like when using HC.Orientation.POINTY the FLAT option works correctly and the grid doesn't have gaps.

To Reproduce My configuration is this:

const hexTile = HC.defineHex({
    dimensions: { xRadius: 1.05, yRadius: 1.05},
    orientation: HC.Orientation.POINTY,
    offset: 1.0
  })

const spiralGrid = new HC.Grid(hexTile, HC.spiral({ radius: 3 }));
const _spiralGridArray = spiralGrid.toArray()

from there I use the _spiralGridArray x, y to construct the grid tiles.

Expected behavior Work like FLAT which produces a correct result

Environment (please complete the following information):

Screenshots image

Additional context Add any other context about the problem here.

flauwekeul commented 8 months ago

This is exactly the expected behavior when you define the hexes pointy, but render them flat (as seen in the screenshot). When you define the hexes pointy, you probably want to render them pointy as well and it seems that's not happening.

netgfx commented 8 months ago

Not sure I follow, is there something special to consider in order to render them pointy? Should they be rotated or something else? My expectation was that since x, y are actual coordinates and not 0,1 they would automatically fit with one another, FLAT seems to work this way because I'm not doing anything special, unless I'm missing something. Thanks for your response btw, really appreciate it!

flauwekeul commented 8 months ago

Could you share the code where you render a hex?

The docs have examples for rendering, if you hadn't found them already.

netgfx commented 8 months ago

Sure so I'm using R3F (threejs in react) to render them. This takes place here: https://codesandbox.io/p/sandbox/hex-grid-ts-732n3c?file=%2Fsrc%2Fgrid%2FInstancedMeshWithUniforms.tsx%3A42%2C1

Specifically:

for (let i = 0; i < currentGridArray.length; i++) {
        mat4.setPosition(currentGridArray[i].x, currentGridArray[i].y, 0)
        objRef.current.setMatrixAt(i, mat4)
 }

The grid is created here: https://codesandbox.io/p/sandbox/hex-grid-ts-732n3c?file=%2Fsrc%2Fgrid%2FHexGrid.tsx%3A133%2C15

const hexTile = HC.defineHex({
    dimensions: { xRadius: X_RADIUS, yRadius: Y_RADIUS },
    orientation: HC.Orientation.POINTY,
    offset: 1.0
  })

const spiralGrid = new HC.Grid(hexTile, HC.spiral({ radius: HEX_SIZE }))
const _spiralGridArray = spiralGrid.toArray()
flauwekeul commented 8 months ago

You're calling defineHex() in two places (both in /src/grid/HexGrid.tsx), one with orientation flat (line 23) and one with orientation pointy (line 40). If you use the same orientation for both calls to defineHex(), it seems to be rendered as expected.

netgfx commented 8 months ago

Hm it doesn't for me and it shouldn't matter because the getHexNeighbors is only used for pathfinding not for the grid rendering. Only the hexTile on line(38) is used for rendering. I guess I could render with Flat and then rotate the whole grid but I just wanted to see if I was doing something wrong with Pointy

flauwekeul commented 8 months ago

I checked the value of currentGridArray[0].orientation on line 47 of src/grid/InstancedMeshWithUniforms.tsx and I got 'pointy', when it should be flat, right? Do you have the same?

netgfx commented 8 months ago

I got pointy image It shouldn't be Flat because the hexTile is

 const hexTile = HC.defineHex({
    dimensions: { xRadius: X_RADIUS, yRadius: Y_RADIUS },
    orientation: HC.Orientation.POINTY,
    offset: 1.0
  })

So I think the points array is having the correct data

flauwekeul commented 8 months ago

Sorry, I misunderstood. I'll try again later. They're rendered as flat hexes, so the problem should be where the individual hexes are rendered

flauwekeul commented 8 months ago

Could it be that in HexGeometry.ts you're always rendering flat hexes (lines 8-15)? If so, you could fix it by using hex.corners (which is an array of { x: number, y: number }) to draw a hex shape. These corners are different based on the orientation.

netgfx commented 8 months ago

Hm I see, unfortunately that would mean I would have to make one geometry for each tile which would result in a loss in performance as now I'm using a single cached geometry for all tiles as they are instanced. If that is the only way to render Pointy correctly I guess I would have to use Flat which is working correctly

flauwekeul commented 8 months ago

Instead of one cached geometry, you can simply make two: one for pointy and one for flat. The shape is the same for all tiles per orientation.

netgfx commented 8 months ago

I thought I needed to use the corners of the currentGridArray and each index has its own corners values. Is there an algorithm I can use to create the geometry for the Pointy like I have for Flat?

flauwekeul commented 8 months ago

Looks like this creates a pointy geometry (I've swapped Math.cos and Math.sin on lines 12-13 in HexGeometry.ts):

const x = hexSize * Math.sin(angle)
const y = hexSize * Math.cos(angle)
netgfx commented 8 months ago

Ah yes this works perfectly! Thank you so much for your tenacity in this issue and great support, I hope this is useful for others as well. Your library was the only one that was easy to implement and understand out of the box within a few minutes!