GridMap: Add hexagonal cell support - #9
Open
dsarno wants to merge 2 commits into
Open
Conversation
Add a `cell_shape` property to `GridMap` that selects between square and hexagonal cells, along with the editor support needed to author hex maps. `GridMap`: - Hexagonal cells are regular (all sides equal). `cell_size.x` holds the cell radius (center to vertex) and `cell_size.y` the cell height; `cell_size.z` is kept in sync with `cell_size.x`. - Hex cells are addressed with axial coordinates, stored as (q, level, r) in the x/y/z fields of the cell `Vector3i`. - Hex cells use their own orientation set: six 60 degree steps about the Y axis, and the same six again after flipping the tile over. - Add `local_region_to_map()` returning every cell index inside an axis-aligned box given in local space. - Add `get_cell_neighbors()` returning the indices adjacent to a cell. - Add a `cell_shape_changed` signal. `GridMapEditor`: - Rotate hex tiles in 60 degree steps about the Y axis, and flip them over about the X/Z axis. - Add the Q/R/S editing axes used by hex maps, and cycle through them with the existing axis shortcuts. - Draw the selection as a per-cell multimesh rather than a bounding box, so the selected cells are unambiguous for hex shapes. - Update fill, clear, duplicate and paste for hex cells. - Fix the floor grid being drawn offset from the level being edited. The editor previously reimplemented `GridMap`'s cell addressing in several places, which does not survive a second cell shape. It now asks `GridMap` to map between local space and cell indices. Co-authored-by: David M. Lary <dmlary@gmail.com> Co-authored-by: Chad Stewart <chad@binarysolo.com>
`GridMap`: - `axial_round()` compared the coordinate remainders with the integer `abs()`, which truncated both to zero and always rounded towards the Q axis. Points off the center of a hexagon were mapped to the wrong cell; use `Math::abs()` and `Math::round()`. - `make_baked_meshes()` still placed each cell with the rectangular layout, so baking a hexagonal map moved every mesh. - Keep the cell orientations in static tables instead of a `TypedArray<Basis>`. Reading one boxed a `Basis` into a `Variant`, and that happens once per cell in `_octant_update()`, `get_meshes()` and `make_baked_meshes()`. - Reject out-of-range values in `set_cell_shape()`, and skip the octant rebuild when the shape does not actually change. - Take `Vector3i`/`Vector3` arguments by const reference, and build the neighbor offsets as `Vector3i` rather than round-tripping them through floating point. `GridMapEditor`: - Free the cursor mesh, the cursor instance and the selection multimesh instance when the editor is destroyed; they leaked their RIDs. - `GridMapEditorPlugin.set_selection()` takes cell coordinates, but the selection is kept in local space, so convert before applying it. - Do not shift the selection tiles by half a cell on X and Z for hexagonal cells, whose position never includes the centering offset. - Use `free_rid()` rather than the deprecated `RenderingServer::free()`, and stop shadowing a member with a local named `shortcut`. Tests: - Cover the position of baked meshes for both cell shapes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds hexagonal cells to
GridMapalongside the existing square ones: axial coordinate mapping, hex-aware cell/world conversion, selection and paste in local space, hexagonal grid and selection drawing, and editor support for the six edit planes.modules/gridmaponly, plus its tests and class reference.Provenance
The first commit is third-party work, squashed and rebased onto current
masterwith original authorship preserved (Casper Beyer, co-authored by David M. Lary and Chad Stewart). It was 6,875 commits behind; 5 files conflicted and the editor plugin alone had 22 conflicting hunks. The second commit is review fixes.This branch was produced by an AI agent. Everything below was verified by building and running it, but it warrants a human read.
Conflict resolution worth knowing about
Upstream had moved on substantially in the same files, so several conflicts were semantic rather than textual:
edit_axis_select+viewport_axis+ a_get_edit_axis()viewport override. Adopted upstream's machinery retyped to the 6-value axis; the viewport-derived Z maps to R for hex.clipboard_is_move/_setup_paste_mode/ preview-restore undo, re-expressed against the local-space clipboard by addingClipboardItem::source_cell.Z/Cto plane rotation, but upstream now uses those for Fill and Duplicate. The two new shortcuts are registered with no default key — see open questions.Defects found and fixed
High —
axial_round()used integerabs(). The fractional remainders were truncated to0before comparison, so any point that wasn't dead-centre in a hexagon could resolve to the wrong cell. One character (Math::abs), but it silently broke everylocal_to_map()call for hex.High —
make_baked_meshes()kept rectangular placement. Baking a hex map displaced every mesh, because the bake path computed positions directly instead of going throughmap_to_local().Medium —
cell_orientationswas aTypedArray<Basis>. Every read heap-allocated aBasisinside aVariant, once per cell in_octant_update(),get_meshes()andmake_baked_meshes(). Replaced with static tables exposed asSpan<const Basis>.Medium — RID leaks.
cursor_mesh,cursor_instanceandselection_multimesh_instancewere never freed; confirmed via editor-exit leak reports, and gone after the fix._update_selection()also left a dangling RID that would double-free on the next call.Public API bug —
GridMapEditorPlugin.set_selection()passed cell coordinates into a local-space setter.Also fixed while merging: multimesh instances allocated for plane-filtered-out cells;
_get_selected_cells()/_get_selection()iterating local-space floats as cell indices; a nullRef<Mesh>dereference for meshless clipboard items;if (int index = ... != -1)in_update_options_menu(); a duplicate "Settings…" menu entry; a#defineleaking from a header;node == NULL; and-Wshadow/ deprecated-free()warnings.Testing
*GridMap*: 9 cases / 250 assertions, all passing. Full suite 1423/1424 — the single failure is an IPv6 test that is environmental and fails onmasterhere too.Revert-proof: reverting the two High fixes makes 2 cases / 17 assertions fail — 16 in
local_to_map() for hex cells(e.g.(2,0,-1) == (1,0,0)) and 1 in the new baked-mesh placement case. Restoring returns 250/250.Also verified:
clang-formatclean,--doctoolregenerates the class reference with zero diff, no compiler warnings inmodules/gridmap, and an editor smoke test on a hex-GridMapscene starts and exits cleanly with no leaks.Open questions for review
get_octants_in_bounds()/get_used_octants_in_bounds()and octant debug visualisation are wrong for hex. They divide local bounds bycell_size, but an octant of axial cells is a rhombus in local space. This needs a semantic decision rather than a mechanical fix, so it was left alone._editor_floor_meta changed fromVector3to a 6-planePackedInt32Array. Existing scenes lose their remembered editor floor once.Generated by Claude Code