Flat-top hexagon geometry, addressed the same way a square grid is: x the column, y
the row, both integers - which is what lets mwg/roguelike's Level (grid logic) and
mwg/render's TileMap (pixel positions) each reuse it without depending on the other.
It lives in mwg/core for exactly that reason: neither of those two modules is allowed
to depend on the other, and this needs to sit below both.
Internally this converts to and from cube coordinates (x + y + z = 0) for every
calculation, because the six neighbour directions are then a fixed, orientation-agnostic
list rather than a column-parity-dependent table someone has to get right twice. The
offset "odd-q" scheme below - odd columns pushed half a row down - is what makes that
cube math round-trip back to integers; nothing about it is rot.js's, which is deliberate
(see the roadmap: rot.js's own hex Path topology is doubled-width coordinates built for
pointy-top hexagons, and does not match this orientation).
Flat-top hexagon geometry, addressed the same way a square grid is:
xthe column,ythe row, both integers - which is what letsmwg/roguelike'sLevel(grid logic) andmwg/render'sTileMap(pixel positions) each reuse it without depending on the other. It lives inmwg/corefor exactly that reason: neither of those two modules is allowed to depend on the other, and this needs to sit below both.Internally this converts to and from cube coordinates (
x + y + z = 0) for every calculation, because the six neighbour directions are then a fixed, orientation-agnostic list rather than a column-parity-dependent table someone has to get right twice. The offset "odd-q" scheme below - odd columns pushed half a row down - is what makes that cube math round-trip back to integers; nothing about it is rot.js's, which is deliberate (see the roadmap: rot.js's own hexPathtopology is doubled-width coordinates built for pointy-top hexagons, and does not match this orientation).Example