Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support hexagon tiles in GridMap #59842

Closed

Conversation

octetdev2
Copy link
Contributor

@octetdev2 octetdev2 commented Apr 3, 2022

This adds support for hexagonal grids in the GridMap node with the same offset and layout semantics as TileMap.

Closes godotengine/godot-proposals#4337

@octetdev2 octetdev2 force-pushed the feat-grid-map-hexagonal-cells branch 2 times, most recently from 46b313a to 8339403 Compare April 3, 2022 17:59
@Calinou Calinou added this to the 4.0 milestone Apr 3, 2022
@octetdev2 octetdev2 force-pushed the feat-grid-map-hexagonal-cells branch from 8339403 to fb03519 Compare April 3, 2022 18:29
@octetdev2 octetdev2 marked this pull request as ready for review April 4, 2022 04:07
@octetdev2 octetdev2 requested a review from a team as a code owner April 4, 2022 04:07
@octetdev2 octetdev2 force-pushed the feat-grid-map-hexagonal-cells branch from fb03519 to cedf45c Compare April 4, 2022 16:11
Copy link
Contributor

@fire-forge fire-forge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it and it works really well. Just a few things need to be changed/fixed:

  • The editor grid drawing should be changed to respect cell_shape and cell_offset_axis settings like the TileMap editor grid does.
  • cell_offset_axis only works in hexagon mode, so you can't use offset squares like you can in TileMaps.
  • The placement position in the editor is off by about half of a cell. This is more apparent when you go into the Top Orthogonal camera mode when drawing on the GridMap. Disabling cell_center_x/y/z makes it off by half of a cell in the opposite direction.

modules/gridmap/doc_classes/GridMap.xml Outdated Show resolved Hide resolved
modules/gridmap/doc_classes/GridMap.xml Show resolved Hide resolved
modules/gridmap/doc_classes/GridMap.xml Show resolved Hide resolved
modules/gridmap/grid_map.cpp Outdated Show resolved Hide resolved
@octetdev2 octetdev2 force-pushed the feat-grid-map-hexagonal-cells branch from cedf45c to e4e5298 Compare April 5, 2022 05:05
@octetdev2
Copy link
Contributor Author

octetdev2 commented Apr 5, 2022

Appreciate the review @fire-forge

The editor grid drawing should be changed to respect cell_shape and cell_offset_axis settings like the TileMap editor grid does.

Was going to split this out into a follow up pull request, but I've squashed it into this one and force pushed.

cell_offset_axis only works in hexagon mode, so you can't use offset squares like you can in TileMaps.

Yes, there is no half offset square shape yet (out of scope for this pull request). But the inspector should disable the options when not applicable.

The placement position in the editor is off by about half of a cell. This is more apparent when you go into the Top Orthogonal camera mode when drawing on the GridMap. Disabling cell_center_x/y/z makes it off by half of a cell in the opposite direction.

I can't reproduce this? The transform for cursor instance and rendering instance should be identical.

My bad, had some staged changes remaining 🙃

@octetdev2 octetdev2 force-pushed the feat-grid-map-hexagonal-cells branch 3 times, most recently from 0f643f5 to d835d1e Compare April 7, 2022 19:12
@fire-forge
Copy link
Contributor

fire-forge commented Apr 7, 2022

I can't reproduce this? The transform for cursor instance and rendering instance should be identical.

I meant that the mouse cursor position vs. which cell it decides you're hovering over is about half a cell off, not the cursor and rendering instance being off. I'll try to get a video of it, and I'll check if it happened before this PR too.

Nevermind, glad to hear it's fixed.

@octetdev2

This comment was marked as outdated.

@octetdev2 octetdev2 force-pushed the feat-grid-map-hexagonal-cells branch 2 times, most recently from f059344 to 2b0f3a6 Compare April 9, 2022 07:30
Copy link
Contributor Author

@octetdev2 octetdev2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, multiplying this twice would be the cause of that extra offset (which was only observable depending on cell size).

modules/gridmap/grid_map.cpp Outdated Show resolved Hide resolved
modules/gridmap/grid_map.cpp Outdated Show resolved Hide resolved
modules/gridmap/grid_map.cpp Outdated Show resolved Hide resolved
@octetdev2 octetdev2 force-pushed the feat-grid-map-hexagonal-cells branch from 2b0f3a6 to ffd5256 Compare April 10, 2022 19:00
@octetdev2
Copy link
Contributor Author

  • Figured out the property validator and disabled the properties for square cells.
  • Also squashed the off by one error when picking (off by one extra pass of multiplication 😆).

@octetdev2 octetdev2 changed the title Support hexagonal cells in GridMap Support hexagon tiles in GridMap Apr 13, 2022
@octetdev2 octetdev2 force-pushed the feat-grid-map-hexagonal-cells branch 2 times, most recently from eb97e53 to 192d579 Compare April 14, 2022 14:36
@Wasabi-Cheetah
Copy link

I'm just going to post this here for anyone else looking for a hexagon grid system for a sphere as well. https://stackoverflow.com/questions/46777626/mathematically-producing-sphere-shaped-hexagonal-grid

@soft-circles
Copy link

I would love to see this feature merged, any chance this will make it in during the Godot 4 beta?

@Calinou
Copy link
Member

Calinou commented Jan 20, 2023

I would love to see this feature merged, any chance this will make it in during the Godot 4 beta?

Godot 4.0 is in feature freeze, so any features of a significant size are postponed to future 4.x releases.

Also, this pull request needs to be rebased before it can be merged.

@DeletedBunny
Copy link

Would love to see this in 4.1. I was looking for different ways to extend gridmap but this does exactly that! Very useful feature for 4x style games or turn based RPGs like Expeditions Rome. Hexes are everywhere in today's games, they should be in Godot!

@gulagkulak
Copy link

@octetdev2 seems to have disappared from the internet (I hope he's ok) so, uh, can someone please take over development of this feature?

@BSChad
Copy link

BSChad commented Dec 7, 2023

Since the original maintainer seems to have vanished, I took a shot at updating this branch with the latest master. I've never actually contributed before. https://github.com/BSChad/godot/tree/feat-grid-map-hexagonal-cells

Would I just open a new PR?

@Calinou
Copy link
Member

Calinou commented Dec 7, 2023

Since the original maintainer seems to have vanished, I took a shot at updating this branch with the latest master. I've never actually contributed before. BSChad/godot@feat-grid-map-hexagonal-cells

Would I just open a new PR?

Yes, I suggest opening a new PR. That said, consider godotengine/godot-proposals#4337 (comment) as well. The idea of hexagon tiles seems to be well-accepted by now, but some of the advanced options introduced in this PR may be too complex to initially implement.

@AThousandShips
Copy link
Member

Salvaged in: #85890

@AThousandShips AThousandShips removed this from the 4.x milestone Dec 7, 2023
dmlary added a commit to dmlary/godot that referenced this pull request May 11, 2024
The offset-based indexing approach offered many options for mapping
points into map indexes, but the current code had problems correctly
mapping various regions of a cell consistently
(godotengine#85890 (comment)).
Looking at the layout code, there were a lot of options with various
mathematical transforms for each one; verifying where the issue was, and
if it affected the other layouts was challenging.

There is also a comment at the top of the PR (godotengine#85890), and in the
discussion for the previous PR (godotengine#59842) about reducing the complexity of
this PR by removing the mixture of cell layout and orientation options.
That seemed like the best approach.

In this commit, I remove the existing layout & orientation options and
replace them with a single coordinate system (axial coordinates
described in
https://www.redblobgames.com/grids/hexagons/#coordinates-axial), and a
single cell orientation (pointy, previously the vertical orientation).

In addition I added tests for `GridMap::local_to_map()` and
`GridMap::map_to_local()` to verify we can correctly identify the edges
of the cell.

With this change we loose the ability to have irregularly shaped hexagon
cells where not all sides are the same length.  This is a side effect of
the current implementation of the algorithm to map between axial and 3d
coordinates.  I don't think this will be a big problem as most hex-based
3d games are using regular hexagons.
Adriankhl pushed a commit to Adriankhl/godot that referenced this pull request Jun 6, 2024
`GridMap` for square tiles needed to support 24 different orientations.
When hexagonal tile support was added, the hex tiles were being rotated
as they were cubes, 90 degrees on whichever axis.  This does not work
for hexagonal tiles.

Hex cell rotation is 60 degrees around the y-axis for 6 possible
orientations, then 180 degrees around the x-axis or z-axis (flipping the
tile over).  Any other rotation around x/z would cause a hex tile to
clip any neighboring cells. This results in 12 possible orientations for
hex cells in a GridMap.

In this commit, I added the hex-specific orientations to the GridMap,
along with the 60/180 degree rotations in the GridMap editor plugin.

In addition, I added `Math_SQRT3` as it is used within the hex
orientation.

GridMap: use axial coordinate system for hex cells
The offset-based indexing approach offered many options for mapping
points into map indexes, but the current code had problems correctly
mapping various regions of a cell consistently
(godotengine#85890 (comment)).
Looking at the layout code, there were a lot of options with various
mathematical transforms for each one; verifying where the issue was, and
if it affected the other layouts was challenging.

There is also a comment at the top of the PR (godotengine#85890), and in the
discussion for the previous PR (godotengine#59842) about reducing the complexity of
this PR by removing the mixture of cell layout and orientation options.
That seemed like the best approach.

In this commit, I remove the existing layout & orientation options and
replace them with a single coordinate system (axial coordinates
described in
https://www.redblobgames.com/grids/hexagons/#coordinates-axial), and a
single cell orientation (pointy, previously the vertical orientation).

In addition I added tests for `GridMap::local_to_map()` and
`GridMap::map_to_local()` to verify we can correctly identify the edges
of the cell.

With this change we loose the ability to have irregularly shaped hexagon
cells where not all sides are the same length.  This is a side effect of
the current implementation of the algorithm to map between axial and 3d
coordinates.  I don't think this will be a big problem as most hex-based
3d games are using regular hexagons.

GridMap: support Center-y for hex cells

GridMapEditor: fix floorgrid offset issue

Currently if you exit editing a GridMap on floor != 0, when you return
to the GridMap the floor grid will be redrawn offset from the cusor.  So
the cursor is at floor 0, but the grid is drawn for floor -1.

The cause of this is `_draw_floor_grid()` takes into account the current
floor level when creating the floor grid.  The problem is that the grid
should be created at floor = 0, as it is offset by the floor number when
displayed.

This commit I removed the floor number argument from
`_draw_floor_grid()`.  As a result the floor grid is generated with
coordinates for floor == 0, and is correctly offset now.

HexGridEditor: fix for x-plane editing hex cells

With the conversion to axial coordinates for hex cells, editing cells
along the x-plane caused cells to be drawn in the wrong place.  It
turned out this was because `GridMapEditor::do_input_action()` assumed
it could modify the floor value directly after calling
`GridMap::local_to_map()`.  This looks like it was a workaround for
floating point errors that occur when raycasting against the picking
plane.

This causes a problem with hex cells as the axial coordinate system
means more math is required to set the x value.

In this commit I remove the code that modifies the floor/plane value for
the cell, and instead move the raypicking plane into the middle of the
cell plane. This will eliminate the majority of raypicking errors that
result from being directly on the edge of the cell.

GridMapEditor: cell selection for hex shaped cells

* GridMap: Add `local_region_to_map()` to get cell indices within a
  bounding box
* GridMap: Added `cell_shape_changed` signal to GridMap
* GridMapEditor: Update grid floor when cell shape changes
* GridMapEditor: Add cell shape mesh for hex tiles
* GridMapEditor: Update tile selection mesh when cell shape changes
* GridMapEditor: Fill selection for hex shaped cells
* GridMapEditor: Clear selection for hex shaped cells
* GridMapEditor: Paste for hex shaped cells

GridMapEditor: Hex cell Q/R/S Axis editing support

Editing along the Z-axis with hex cells results in unexpected behavior
for users as cells will be placed in a zig-zag pattern.  This is because
with pointy orientation, the cell centers are offset every other row as
you move along the Z-axis.

In this commit, I added support for editing cells along the Q-axis
(northwest to southeast), and S-axis (southwest to northeast).  The
terms come from the axial coordinate system used in GridMap, and
derrived from:
https://www.redblobgames.com/grids/hexagons/#coordinates-axial

The Z and C hotkeys were repurposed to rotate around the various non-Y
axis options when using hex-shaped cells, using X, Q, Z, then R axis
when rotating clockwise (hotkey C), and the reverse for
counter-clockwise (hotkey Z). For square-shaped cells, these hotkeys
still map to the X-axis and Z-axis.

This commit does not include required changes to the `GridMap` editor
menu to show/hide the hex-specific axis.

Note, also this commit in particular removes code for functionality that
has been broken for some time.  PR godotengine#25406 Added support for using
Shift-Q and Shift-E to expand selection regions to other planes/floors
without changing the actual floor.  This does not function in 4.2.2.  It
looks like at some point the keybindings for change level were changed
from an accelerator to a shortcut, and the code for checking for the key
combination was not updated.

As the functionality does not currently work, and it's non-trivial to
reimplement with hex cells, I'm leaving it out for the time being.
A dedicated PR should be opened to expand selection capabilities within
the GridMapEditor later to re-introduce the functonality.

GridMapEditor: Menu updates for Q/R/S axis editing

GridMap: Fix get_meshes() for NavMesh generation

Needed to update GridMap::get_meshes() to use map_to_local() instead of
manually calculating transforms.

GridMap: Add get_cell_neighbors()

With the transition to axial coordinates for hex shaped cells in
GridMap, it became more difficult to navigate grid map cells to their
neighbors.  This is because the Q/R axial coordinates do not directly
map to x/y equivalents.

In this commit I add GridMap::get_cell_neighbors() which is the minimum
implementation required to map from a GridMap to an AStar3d without
duplicating the axial coordinate math.

This commit should be expanded on to add direction-based neighbor
functions, but I'd rather do that work in a dedicated PR to abstract
navigating cell indexes into a dedicated class for each cell type.

GridMapEditor: Use multimesh for cell highlighting

Minor perf improvement to switch selection to use a multimesh for
highlighting selected cells.

GridMapEditor: Add lines around selection tiles

HexGridEditor: Fix editing grid for Q/R/S axis

GridMapEditor: selection on Q/S planes fixed

Selection along the Q & S planes was selecting a cube volume due to
`GridMap::local_region_to_map()` using the two points as the corners of
an AABB.  This isn't a problem when editing on X/Y/Z planes as the begin
and end points share one common value for at least one of their indices.
The Q & S planes on the other hand, run diagonal across the X/Z
coordinates, so every selection is a cube traversing X/Z.

In this commit I add support for selecting along the Q/S plane.  To do
this, GridMapEditor will now prune the selection region returned from
`GridMap::local_region_to_map()` based on which axis is being edited.

In addition, I trimmed out a lot of extranous values & logic that
weren't being used in the selection code.

GridMapEditor: Update X-Axis grid for hex cells
dmlary added a commit to dmlary/godot that referenced this pull request Jun 30, 2024
* `GridMap`
    * Added hex cell orientations (they differ from square orientations)
        * 60 degree steps about Y axis
        * 180 degree step about X axis to flip tile over
    * Use axial coordinate system for hex cells
        * https://www.redblobgames.com/grids/hexagons/#coordinates-axial
        * Q/R coordinates stored in X/Z fields of Vector3i
            * Preserve Y for level
            * See note below about internal coordinate systems leaking
        * Simplifies many hex-based algorithms (pathfinding, distance,
	  etc)
        * comments on PRs godotengine#85890 & godotengine#59842 suggested simplifying layout &
          orientation options
    * Support only normal hex cells
        * All side lengths are equal
        * Size of hexagon is defined by the radius; distance from center
	  to corners of cell
        * Supporting only normal hexes simplifies all calculations
        * Hex cell radius stored in cell_size.x
    * Add `GridMap::local_region_to_map()` to get cell indices within an
      axis-aligned bounding box
    * Add `GridMap::get_cell_neighbors()` to get cell neighbor indices
    * Add tests for `GridMap::map_to_local()` & `GridMap::local_to_map()`
        * necessary to confirm they were correctly detecting cell bounds
    * Add `cell_shape_changed` signal
* `GridMapEditor`
    * Rotate hex tiles
        * Hex tile rotation is significantly different from square tile
          rotation
        * 60 degree rotation about Y axis
        * 180 degree rotation about X/Z axis (flip tile over)
    * Support additional axes when editing hex cells
        * Q/S axis run northwest and southwest with evenly spaced cells
        * Update X-axis grid to show different cell sizes
        * Z/C shortcuts rotate through non-Y axes when using hex cells
    * Cell selection indicator changed from a bounding box to per-cell
      mesh in a multimesh
        * This was needed to make selection bounds clear when working
          with hex-shaped cells
    * Update fill/clear/duplicate for hex cells
    * Simplified cursor positioning code
    * Simplified selection & paste indicator code
    * Fixed issue where floor grid was drawn offset from the editing level
    * Removed dead code for expanding selection regions to additional
      planes/floors
        * Added in PR godotengine#25406 to expand using Shift-Q & Shift-E
        * Does not function in 4.2.2
        * Broken when keybindings for change level were changed from an
          accelesator to a shortcut
        * Non-trivial to reimplement
* Added `Math_SQRT3` as it is used extensively for hex cells

The internal coordinate system used within `GridMap` should not be
considered to be public or stable.  This has been the assumption up to
this point, and the result has been `GridMapEditor` deeply dependent on
the internal coordinate system.  This commit is so large because much of
`GridMapEditor` assumed it knew how `GridMap` was addressing individual
cells.  Many of those assumptions broke with the addition of hex cells.

Another side effect of leaking the internal coordinate system is the
extensive code duplication that is happening in users' code bases as
they all have to implement common functions for navigating the coordinate
system.  Functions such as calculating area of affect, distance, etc.

In this commit large steps have been made to isolate the coordinate system
to `GridMap`, and helpers added to navigate the coordinate system.
`GridMapEditor` has been updated to rely on `GridMap` to provide the
appropriate mapping from local space to `GridMap` coordinates.

There is more work to be done in this area, but is being held back to
limit the scope of this PR.
BSChad pushed a commit to BSChad/godot that referenced this pull request Jul 23, 2024
* `GridMap`
    * Added hex cell orientations (they differ from square orientations)
        * 60 degree steps about Y axis
        * 180 degree step about X axis to flip tile over
    * Use axial coordinate system for hex cells
        * https://www.redblobgames.com/grids/hexagons/#coordinates-axial
        * Q/R coordinates stored in X/Z fields of Vector3i
            * Preserve Y for level
            * See note below about internal coordinate systems leaking
        * Simplifies many hex-based algorithms (pathfinding, distance,
	  etc)
        * comments on PRs godotengine#85890 & godotengine#59842 suggested simplifying layout &
          orientation options
    * Support only normal hex cells
        * All side lengths are equal
        * Size of hexagon is defined by the radius; distance from center
	  to corners of cell
        * Supporting only normal hexes simplifies all calculations
        * Hex cell radius stored in cell_size.x
    * Add `GridMap::local_region_to_map()` to get cell indices within an
      axis-aligned bounding box
    * Add `GridMap::get_cell_neighbors()` to get cell neighbor indices
    * Add tests for `GridMap::map_to_local()` & `GridMap::local_to_map()`
        * necessary to confirm they were correctly detecting cell bounds
    * Add `cell_shape_changed` signal
* `GridMapEditor`
    * Rotate hex tiles
        * Hex tile rotation is significantly different from square tile
          rotation
        * 60 degree rotation about Y axis
        * 180 degree rotation about X/Z axis (flip tile over)
    * Support additional axes when editing hex cells
        * Q/S axis run northwest and southwest with evenly spaced cells
        * Update X-axis grid to show different cell sizes
        * Z/C shortcuts rotate through non-Y axes when using hex cells
    * Cell selection indicator changed from a bounding box to per-cell
      mesh in a multimesh
        * This was needed to make selection bounds clear when working
          with hex-shaped cells
    * Update fill/clear/duplicate for hex cells
    * Simplified cursor positioning code
    * Simplified selection & paste indicator code
    * Fixed issue where floor grid was drawn offset from the editing level
    * Removed dead code for expanding selection regions to additional
      planes/floors
        * Added in PR godotengine#25406 to expand using Shift-Q & Shift-E
        * Does not function in 4.2.2
        * Broken when keybindings for change level were changed from an
          accelesator to a shortcut
        * Non-trivial to reimplement
* Added `Math_SQRT3` as it is used extensively for hex cells

The internal coordinate system used within `GridMap` should not be
considered to be public or stable.  This has been the assumption up to
this point, and the result has been `GridMapEditor` deeply dependent on
the internal coordinate system.  This commit is so large because much of
`GridMapEditor` assumed it knew how `GridMap` was addressing individual
cells.  Many of those assumptions broke with the addition of hex cells.

Another side effect of leaking the internal coordinate system is the
extensive code duplication that is happening in users' code bases as
they all have to implement common functions for navigating the coordinate
system.  Functions such as calculating area of affect, distance, etc.

In this commit large steps have been made to isolate the coordinate system
to `GridMap`, and helpers added to navigate the coordinate system.
`GridMapEditor` has been updated to rely on `GridMap` to provide the
appropriate mapping from local space to `GridMap` coordinates.

There is more work to be done in this area, but is being held back to
limit the scope of this PR.
BSChad pushed a commit to BSChad/godot that referenced this pull request Jul 24, 2024
* `GridMap`
    * Added hex cell orientations (they differ from square orientations)
        * 60 degree steps about Y axis
        * 180 degree step about X axis to flip tile over
    * Use axial coordinate system for hex cells
        * https://www.redblobgames.com/grids/hexagons/#coordinates-axial
        * Q/R coordinates stored in X/Z fields of Vector3i
            * Preserve Y for level
            * See note below about internal coordinate systems leaking
        * Simplifies many hex-based algorithms (pathfinding, distance,
	  etc)
        * comments on PRs godotengine#85890 & godotengine#59842 suggested simplifying layout &
          orientation options
    * Support only normal hex cells
        * All side lengths are equal
        * Size of hexagon is defined by the radius; distance from center
	  to corners of cell
        * Supporting only normal hexes simplifies all calculations
        * Hex cell radius stored in cell_size.x
    * Add `GridMap::local_region_to_map()` to get cell indices within an
      axis-aligned bounding box
    * Add `GridMap::get_cell_neighbors()` to get cell neighbor indices
    * Add tests for `GridMap::map_to_local()` & `GridMap::local_to_map()`
        * necessary to confirm they were correctly detecting cell bounds
    * Add `cell_shape_changed` signal
* `GridMapEditor`
    * Rotate hex tiles
        * Hex tile rotation is significantly different from square tile
          rotation
        * 60 degree rotation about Y axis
        * 180 degree rotation about X/Z axis (flip tile over)
    * Support additional axes when editing hex cells
        * Q/S axis run northwest and southwest with evenly spaced cells
        * Update X-axis grid to show different cell sizes
        * Z/C shortcuts rotate through non-Y axes when using hex cells
    * Cell selection indicator changed from a bounding box to per-cell
      mesh in a multimesh
        * This was needed to make selection bounds clear when working
          with hex-shaped cells
    * Update fill/clear/duplicate for hex cells
    * Simplified cursor positioning code
    * Simplified selection & paste indicator code
    * Fixed issue where floor grid was drawn offset from the editing level
    * Removed dead code for expanding selection regions to additional
      planes/floors
        * Added in PR godotengine#25406 to expand using Shift-Q & Shift-E
        * Does not function in 4.2.2
        * Broken when keybindings for change level were changed from an
          accelesator to a shortcut
        * Non-trivial to reimplement
* Added `Math_SQRT3` as it is used extensively for hex cells

The internal coordinate system used within `GridMap` should not be
considered to be public or stable.  This has been the assumption up to
this point, and the result has been `GridMapEditor` deeply dependent on
the internal coordinate system.  This commit is so large because much of
`GridMapEditor` assumed it knew how `GridMap` was addressing individual
cells.  Many of those assumptions broke with the addition of hex cells.

Another side effect of leaking the internal coordinate system is the
extensive code duplication that is happening in users' code bases as
they all have to implement common functions for navigating the coordinate
system.  Functions such as calculating area of affect, distance, etc.

In this commit large steps have been made to isolate the coordinate system
to `GridMap`, and helpers added to navigate the coordinate system.
`GridMapEditor` has been updated to rely on `GridMap` to provide the
appropriate mapping from local space to `GridMap` coordinates.

There is more work to be done in this area, but is being held back to
limit the scope of this PR.
BSChad pushed a commit to BSChad/godot that referenced this pull request Sep 17, 2024
`GridMap` for square tiles needed to support 24 different orientations.
When hexagonal tile support was added, the hex tiles were being rotated
as they were cubes, 90 degrees on whichever axis.  This does not work
for hexagonal tiles.

Hex cell rotation is 60 degrees around the y-axis for 6 possible
orientations, then 180 degrees around the x-axis or z-axis (flipping the
tile over).  Any other rotation around x/z would cause a hex tile to
clip any neighboring cells. This results in 12 possible orientations for
hex cells in a GridMap.

In this commit, I added the hex-specific orientations to the GridMap,
along with the 60/180 degree rotations in the GridMap editor plugin.

In addition, I added `Math_SQRT3` as it is used within the hex
orientation.

GridMap: use axial coordinate system for hex cells
The offset-based indexing approach offered many options for mapping
points into map indexes, but the current code had problems correctly
mapping various regions of a cell consistently
(godotengine#85890 (comment)).
Looking at the layout code, there were a lot of options with various
mathematical transforms for each one; verifying where the issue was, and
if it affected the other layouts was challenging.

There is also a comment at the top of the PR (godotengine#85890), and in the
discussion for the previous PR (godotengine#59842) about reducing the complexity of
this PR by removing the mixture of cell layout and orientation options.
That seemed like the best approach.

In this commit, I remove the existing layout & orientation options and
replace them with a single coordinate system (axial coordinates
described in
https://www.redblobgames.com/grids/hexagons/#coordinates-axial), and a
single cell orientation (pointy, previously the vertical orientation).

In addition I added tests for `GridMap::local_to_map()` and
`GridMap::map_to_local()` to verify we can correctly identify the edges
of the cell.

With this change we loose the ability to have irregularly shaped hexagon
cells where not all sides are the same length.  This is a side effect of
the current implementation of the algorithm to map between axial and 3d
coordinates.  I don't think this will be a big problem as most hex-based
3d games are using regular hexagons.

GridMap: support Center-y for hex cells

GridMapEditor: fix floorgrid offset issue

Currently if you exit editing a GridMap on floor != 0, when you return
to the GridMap the floor grid will be redrawn offset from the cusor.  So
the cursor is at floor 0, but the grid is drawn for floor -1.

The cause of this is `_draw_floor_grid()` takes into account the current
floor level when creating the floor grid.  The problem is that the grid
should be created at floor = 0, as it is offset by the floor number when
displayed.

This commit I removed the floor number argument from
`_draw_floor_grid()`.  As a result the floor grid is generated with
coordinates for floor == 0, and is correctly offset now.

HexGridEditor: fix for x-plane editing hex cells

With the conversion to axial coordinates for hex cells, editing cells
along the x-plane caused cells to be drawn in the wrong place.  It
turned out this was because `GridMapEditor::do_input_action()` assumed
it could modify the floor value directly after calling
`GridMap::local_to_map()`.  This looks like it was a workaround for
floating point errors that occur when raycasting against the picking
plane.

This causes a problem with hex cells as the axial coordinate system
means more math is required to set the x value.

In this commit I remove the code that modifies the floor/plane value for
the cell, and instead move the raypicking plane into the middle of the
cell plane. This will eliminate the majority of raypicking errors that
result from being directly on the edge of the cell.

GridMapEditor: cell selection for hex shaped cells

* GridMap: Add `local_region_to_map()` to get cell indices within a
  bounding box
* GridMap: Added `cell_shape_changed` signal to GridMap
* GridMapEditor: Update grid floor when cell shape changes
* GridMapEditor: Add cell shape mesh for hex tiles
* GridMapEditor: Update tile selection mesh when cell shape changes
* GridMapEditor: Fill selection for hex shaped cells
* GridMapEditor: Clear selection for hex shaped cells
* GridMapEditor: Paste for hex shaped cells

GridMapEditor: Hex cell Q/R/S Axis editing support

Editing along the Z-axis with hex cells results in unexpected behavior
for users as cells will be placed in a zig-zag pattern.  This is because
with pointy orientation, the cell centers are offset every other row as
you move along the Z-axis.

In this commit, I added support for editing cells along the Q-axis
(northwest to southeast), and S-axis (southwest to northeast).  The
terms come from the axial coordinate system used in GridMap, and
derrived from:
https://www.redblobgames.com/grids/hexagons/#coordinates-axial

The Z and C hotkeys were repurposed to rotate around the various non-Y
axis options when using hex-shaped cells, using X, Q, Z, then R axis
when rotating clockwise (hotkey C), and the reverse for
counter-clockwise (hotkey Z). For square-shaped cells, these hotkeys
still map to the X-axis and Z-axis.

This commit does not include required changes to the `GridMap` editor
menu to show/hide the hex-specific axis.

Note, also this commit in particular removes code for functionality that
has been broken for some time.  PR godotengine#25406 Added support for using
Shift-Q and Shift-E to expand selection regions to other planes/floors
without changing the actual floor.  This does not function in 4.2.2.  It
looks like at some point the keybindings for change level were changed
from an accelerator to a shortcut, and the code for checking for the key
combination was not updated.

As the functionality does not currently work, and it's non-trivial to
reimplement with hex cells, I'm leaving it out for the time being.
A dedicated PR should be opened to expand selection capabilities within
the GridMapEditor later to re-introduce the functonality.

GridMapEditor: Menu updates for Q/R/S axis editing

GridMap: Fix get_meshes() for NavMesh generation

Needed to update GridMap::get_meshes() to use map_to_local() instead of
manually calculating transforms.

GridMap: Add get_cell_neighbors()

With the transition to axial coordinates for hex shaped cells in
GridMap, it became more difficult to navigate grid map cells to their
neighbors.  This is because the Q/R axial coordinates do not directly
map to x/y equivalents.

In this commit I add GridMap::get_cell_neighbors() which is the minimum
implementation required to map from a GridMap to an AStar3d without
duplicating the axial coordinate math.

This commit should be expanded on to add direction-based neighbor
functions, but I'd rather do that work in a dedicated PR to abstract
navigating cell indexes into a dedicated class for each cell type.

GridMapEditor: Use multimesh for cell highlighting

Minor perf improvement to switch selection to use a multimesh for
highlighting selected cells.

GridMapEditor: Add lines around selection tiles

HexGridEditor: Fix editing grid for Q/R/S axis

GridMapEditor: selection on Q/S planes fixed

Selection along the Q & S planes was selecting a cube volume due to
`GridMap::local_region_to_map()` using the two points as the corners of
an AABB.  This isn't a problem when editing on X/Y/Z planes as the begin
and end points share one common value for at least one of their indices.
The Q & S planes on the other hand, run diagonal across the X/Z
coordinates, so every selection is a cube traversing X/Z.

In this commit I add support for selecting along the Q/S plane.  To do
this, GridMapEditor will now prune the selection region returned from
`GridMap::local_region_to_map()` based on which axis is being edited.

In addition, I trimmed out a lot of extranous values & logic that
weren't being used in the selection code.

GridMapEditor: Update X-Axis grid for hex cells
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.