Any way to make this system work with hexes?

Hello!

I’m wanting to implement this system with hexes. However, I cannot figure out how to use the convert to grid for hexes using the world space.

As hexes overlap and aren’t conformed to a perfect box, this seems like it won’t jive with this kind of system.

Is there a way to adapt this or is it just better to have the raycast hit the hex and the hex object hold its coordinates for reference instead?

2 Likes

It can be done, but it takes a bit of work.
Here’s an example of my TileUtilities class I used in Beneath The Mountain

TileUtilities.cs
using UnityEngine;

namespace TkrainDesigns.Tiles.Grids
{
    public static class TileUtilities
    {
        public static float TileSize = 2.0f;
        const float XFactor = .834f;
        const float YFactor = .956f;

        static float HexGridSizeX => TileSize * XFactor;

        static float HexGridSizeY => TileSize * YFactor;

        static int GridX(Vector3 position)
        {
            return Mathf.RoundToInt(position.x / HexGridSizeX);
        }

        
        static int Xeven(Vector3 position)
        {
            return Mathf.Abs(GridX(position) % 2);
        }

        static int GridY(Vector3 position)
        {
            float offset = HexGridSizeY * Xeven(position) * .45f;
            float zed = position.z - offset;
            return Mathf.RoundToInt(zed / HexGridSizeY);
        }

        static Vector2Int GridPosition(Vector3 position)
        {
            return new Vector2Int(GridX(position), GridY(position));
        }
        /// <summary>
        /// The Position in Hex Tile space for Vector3(x,y,z)
        /// </summary>
        /// <param name="position"></param>
        /// <returns></returns>
        public static Vector2Int ToGridPosition(this Vector3 position)
        {
            return GridPosition(position);
        }

        static Vector3 IdealWorldPosition(Vector2Int location)
        {
            
            {
                
                {
                    float offset = HexGridSizeY * (location.x%2 * .5f);
                    return new Vector3(location.x * HexGridSizeX, 0, location.y * HexGridSizeY + offset);
                }

                
            }
        }
        /// <summary>
        /// The Position in 3D space for a tile located at Vector2(x,y)
        /// </summary>
        /// <param name="location"></param>
        /// <returns></returns>
        public static Vector3 ToWorldPosition(this Vector2Int location)
        {
            return IdealWorldPosition(location);
        }
    }
}

These are basically utilities converting to and from Hexagonal grid positions. The Hexagons are flat side up (there are two distinct Hex schemes, Flat Up, and Corner Up, a Corner Up tile will have flat sides East and West).

Things you have to take into account:

  • The position of an EVEN numbered tile is offset from the position of an ODD numbered tile.
  • There are six directions you can move, which means you need to consider six directions in any given A* or Breadth Depth Search pathfinding algorythm.
  • I never upgraded this to deal with differing heights.

The good news is you still get to work with a 2D GridSystem and LevelGrid. It’s still fundamentally a 2D map, it’s just special math to deal with the directions.

2 Likes

Yup that is absolutely possible, the “shape” or the Grid is just math so if you do some more complex math you end up with a different shape.
This exact scenario, a Hex grid, is exactly what I’d like to do in a future update.

4 Likes

Maybe add 3D too

I would really love to see a future update with the hex grid. Different solutions are always nice to see!

2 Likes

Thank you for sharing this.

You have some ‘magic numbers’ in this class. For example, a .45f sitting in the GridY calculation.

Could you explain them and how you got them?
The .45f, TileSize, and X and Y Factors I’m interested in how you calculated them and what you’re using them for.

Mostly trial and error (lots of error).
The TileSize was derived much like Hugo has determined 2.0f to be a good size for the square tiles. 1 unit just doesn’t give enough elbow room. 2 is a pretty good grid size all around for most styles of games.
The X and Y Factors are the math to account for the difference in size between the widest points of a Hex tile in both the X and Y dimension.
There’s some crazy math you can do to calculate these numbers… For example, to get the Y factor (I really should have did like @CodeMonkey did and used Z when I wrote these formulas!), we’re assuming a tile with the adjacent edges N/S, not E/W. Each Hexagon has six sides, which form six 60 degree triangles that all meet at the center of the triangle. You can then bisect one of these triangles to get a Right Triangle. From there, if you know the length of one of the six edges, you can use trigonometry to derive the distances of the other two edges based on the 30 and 60 degree angles created by our triangle…
At some point, I did all that math. I don’t have my notes, I just have the factors that when multiplied by the tile size give me the X and Y dimensions of the tile.
I made the physical tiles 10% smaller, so that there is a clear gap between each tile, making it easier to see that you’re in a tile based game. I believe that’s where the .45f came into play… Yep, it’s a magic number, and yep, magic numbers are BAD. In fact, I would say that this TileUtilities class has several things that as the TA of the Design Patterns and RPG course would cause me to say "Hey, these are poorly named variables and methods!
In fact, since I used magic numbers, I see a mismatch… because I’m using .45f when calculating a world position into a grid position, but a .5f when calculating a grid position into a world position… ideally, these should be identical.

Remember, this code is several years old. I originally wrote the GridUtilities class when I was taking the 3d course, sometime in 2016 or 17… as I thought I’d be clever and make my Realm Rush game with hex tiles instead of squares. I’m not a fan of diagonal movement in a square tile game, not because it’s hard to do, just because I like the strategy of having to move through each space proper. Hex tiles make that more elegant because the distance from any GridPosition to any of the six cardinal directions in a Hex Tile game are identical. It also creates some interesting strategies when dealing with blocking (I also don’t like when you can walk right through a player or enemy’s position). With WASD only movement, you can block an entrance in such a way that only one enemy can attack… bit trickier when there are six directions…
Anyways, It’s quite possible I’m rambling at this point as it’s 1am.

Here’s a fantastic tutorial on Hex tiles from CatLike Coding.

Hey Brian,

Thank you again for the info!

I’m going to pick your brain once more since the link you put there has amazing information.

If I’m using a hex mesh, say as part of an asset pack, how do you go about getting the proper dimensions for it? If I don’t know the length or even number of units it uses, it makes applying any of the calculations pretty tough.

For example, I don’t know how I’d properly pick a “grid size” since the prefab is unlikely to be a perfect size and match up to unity units (especially since a hex will have to be shorter).

I’m guessing when you mean “factors”, you’re meaning the total distance from the center to the opposite side? (i.e. points up to points down, or middle of flat edge to middle of flat edge)

I have some code working, sort of, using a combination of your class above and some other sources/my own code. However, since I want to use a mesh that I can texture myself, and not sure what the sizes will be, the code doesn’t seem to support these calculations as accurately as I’d like.

Hopefully this makes sense. If you have any resources for getting dimensions of a mesh and the unity space, that’d be great. (Assuming “grid size” should be using unit units.)

If the hex mesh is a perfect hex (six sides, six angles, each side measuring the same, each angle exactly 60 degrees), then it’s just a matter of scaling the mesh to the correct size.

The factors are a simplification of a number of equations. Unfortunately, I don’t have the exact math I used at the time. There’s a good chance, however, that the base equations are hiding somewhere in CatLke’s tutorial. At the time I wrote Beneath, the tutorials I linked to were just the first couple. He’s really expanded it out. I’m actually considering going through them again and adapting things for elevetion (y).

In addition to Catlike Coding (which is great!), check out this post from Red Blob Games (which is also great!):

Also, Unity’s Tilemap can handle hexagonal tilemaps:

2 Likes

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.

Privacy & Terms