[RELEASED] HexKit: hexagon grid tools in C#

1612974--98143--$HexKit-package-small.png

The premier Settworks Unity Package is now available on the Unity Asset Store! Designed for independent developers and hobbyists, HexKit is a streamlined C# resource for handling hexagon grids in your game.

Versatile: One resource, many applications: if you’re using hexagons, this is the tool. HexKit handles everything from basic grid geometry to visibility calculations and pathfinding. It’s suitable for puzzle games, tactical combat, or just drawing a honeycomb.

Accessible: HexKit takes advantage of powerful C# features to maximize the utility of every function, but it doesn’t expect you to have a degree in computer science. The documentation and example code are written with the fledgling designer in mind.

Focused: As a script-only resource, HexKit does one thing and does it well. It doesn’t dictate your workflow and places no constraints on how you manage game data. It fits in right where it’s needed, and stays out of the way elsewhere.

HexKit features include:

  • Iteration over geometric grid areas: lines, rectangles, range-from-center.
  • Movement range calculation supporting non-uniform and asymmetric movement costs.
  • Pathfinding to a single known target, or to the nearest target satisfying a test function.
  • Fast, accurate line-of-sight tests, and full field-of-view using real arcs for perfect shadows.
  • Simple hexagon mesh generation, ideal for fast prototyping. The logo above was generated from the HexKit code example, using no other assets.
    The full documentation for HexKit can be viewed here, and its official forum is located here. Try out the hands-on demo, built from the included example code!

Looking forward to testing this out.

Currently working on some improvements for v1.1, including a few good ideas from reddit.

HexCoord will gain several new methods to simplify common operations. My favorite is static CartesianRectangleBounds, which returns the corners of a QR-space rectangle that includes every cell intersected by a real-space rectangle. Give it the worldspace corners of your viewport, and it will give you the minimal HexCoord corners that include all the partial hexes at the edge.

To HexKit proper, I’m adding a Radiate variant that accepts an Opacity delegate similar to the MoveCost variant for pathfinding, so that obstructions can reduce the range of vision beyond them rather than blocking it completely.

Finally, the example scene will be getting a bit of love. Top priority is to demonstrate HexCoordinate by loading and saving a grid configuration, and if time allows I’ll try to spruce up the UI as well.

I found a couple of bugs, and getting the fixes out is more important than waiting for a few more features. Version 1.1 is submitted to the Asset Store and should be live in a couple of days, but since all the important changes were in HexCoord, you can download them right now from GitHub. I have already updated the online documentation as well.

HexCoord changes:

  • Fixed a bug in HexCoord.IsWithinRectangle which caused an incorrect right-hand border in certain cases. This did not affect HexKit.WithinRectangle.
  • Completely rewrote GetHashCode. The old one was bad and I feel bad. How bad? Due to dramatic reduction in hash collisions, HexKit pathing functions are about 15x faster now.
  • Fixed a bug in SextantRotation which somehow crept in after I tested it.
  • New instance methods: IsOnCartesianLine, IsOnCartesianLineSegment. These test whether a line or line segment touch a particular hex.
  • New instance method: HalfSextant. CornerSextant and NeighborSextant can both be derived from this.
  • New static methods: NormalizeRotationIndex, IsSameRotationIndex. These simplify working with neighbor, corner, polar, etc. indexing. (Note that index arguments to HexCoord methods are internally normalized, and don’t need to be preprocessed.)
  • New static method: CartesianRectangleBounds. Finds the smallest hex-grid rectangle containing all hexes touching a real-space rectangle, including partial overlap.

In the full package, HexKit contains only minor tweaks to utilize some new HexCoord features (no behavior changes). The example scene now demonstrates using CartesianRectangleBounds to find all visible hexes.

Development of v1.2 is ongoing, and I intend to publish it before the end of the month. My primary focus so far has been retrofitting Radiate() (the generalized field-of-view method) to support partial shadows, and it’s a monstrous ball of edge cases. A couple more features have snuck into HexCoord in the process, as well as an option on the current binary-shadow Radiate() to return obstacles as “lit” when appropriate (current behavior, and default from 1.2, considers all obstacles to be dark).

I’ve received a couple of suggestions for additional features. Other short-list goals for either 1.2 or 1.3 are the beginnings of some editor integration with a grid-snap tool for object placement, and extending the basic mesh generation to make compound meshes, including arbitrary “outer border” group meshes, similar to Civ5’s cultural borders.

Also on the horizon is some improvement to the supplied example scene, partly for better presentation but also to demonstrate how the features work and how to use them. A particularly good suggestion was to include basic save/load of object layouts. Expect improvements here starting from v1.3.

I’d like to close with a big thank you to everyone who’s bought HexKit so far. The few comments I’ve received have been positive and many have contained constructive suggestions (some reflected above), and hopefully the absence of other comments at least indicates satisfaction with the purchase!

Looking forward to future versions.

Hi!

Just bought your tool – it looks very promising and I think it will fulfil my hex needs. I’m not a programmer - I am game designer, so forgive my ignorance in programming. I have a problem creating a hexgrid that I need for my prototype and maybe you can help me with that.

I have a texture that represents gameboard. I need to add a hexgrid to this board. The board dimensions are 10x15 hexes. I need to match the size of the hex to the size of hex on a gameboard. How can I do this? !

First of all, thanks!

When working out the dimensions of a hexagon, it’s easiest to think of it as a collection of six equilateral triangles which share one corner at the center. You can easily see that the distance between two opposite corners of the hexagon is equal to two triangle sides. Internally, HexCoord assumes each side has a length of 1 and the hexagons are oriented with corners at top and bottom (i.e. on the Y axis), so the height of a hexagon is 2. The width can be found by dividing the internal triangles in half to make two right triangles, then applying the Pythagorean theorem – it works out to the square root of three, which is precalculated as HexCoord.SQRT3.

The easiest solution is to match the size of your assets to these dimensions. But if you’ve already got a bunch of stuff built around other dimensions, it’s still pretty easy to glue them together. Make an empty game object, with no renderer – just a Transform component. Set the X and Y scale to the ratio between your existing asset sizes and HexCoord’s assumed dimensions. For instance, if you’ve been running with the assumption that hexes are 1 unit tall, scale to 0.5 so HexCoord’s 2-unit height matches. If you set the width between parallel sides to 1, use 0.5 / SQRT3, approximately 0.57735. Etc. Now, use this object as the parent for anything that has its location set by HexCoord.Position(). You can also rotate the parent object if you want the flat sides on top and bottom, or if you want to use a plane other than XY.

Edit: There might be cases where the scaled parent trick means you have to re-scale some child objects because of their model sizes. If this turns out to be an issue, you can instead do the same scaling in code: multiply the Vector2 returned by HexCoord.Position() by the appropriate factor to scale positions but not sizes. You can still use a parent for rotation if needed.

I hope this is the info you needed. If you need any more help, or if I answered the wrong question, let me know!

Thanks!

You answer solves one of my problems and I’m grateful, but I’ll need more help :). In the example scene you set the hexgrid that covers whole screen. I need to create a hexgrid that will take only a small part of the screen - the board itself takes just a fragment of the screen. I don’t know how to to this - can you help me with that?

I’m going to assume the board is rectangular, and you know exactly how many hexes wide and tall you want it to be. Then, you can set your corners using the “offset” coordinate system. (If you want the details of what this means, check out Hexagonal Grids)

If (0,0) is at the center of the board:

HexCoord lowerLeft = HexCoord.AtOffset( Mathf.FloorToInt(boardWidth / -2.0f), Mathf.FloorToInt(boardHeight / -2.0f) );
HexCoord upperRight = HexCoord.AtOffset( boardWidth / 2, boardHeight / 2 );

Or if (0,0) is at the lower left:

HexCoord lowerLeft = HexCoord.Origin;
HexCoord upperRight = HexCoord.AtOffset(boardWidth, boardHeight);

The lowerLeft and upperRight here are the same as bounds[0] and bounds[1] in the example script. If you want to set up your board the same way I did, just replace the first two code lines of Start() with those above – if you change the names back to bounds[0] and bounds[1] you can use the example code directly. (Leave off the HexCoord at the start of each line, since the bounds array is already declared at the top.)

Thank you so much!

It worked wonders and I think I’m starting to understand how HexCoord works - the article from redblobgames helped me a lot. Now I only have to figure out the pathfinding and my prototype will be almost done :).

Unity 4.5 serializes structs, so it looks like the HexCoordinate encapsulation class looks is no longer necessary!

Confirmed that HexCoordinate is obsolete! The trade-off is that HexCoord’s fields can’t be read-only, but I’ll happily exchange “ideal” for “convenient” in this case.

Editor integration begins: version 1.2 will contain HexLocation and HexFacing behaviors which can be attached to game objects. HexLocation allows you to position things by specifying hex grid coordinates, and optionally snap to grid positions when moving the object normally. HexFacing performs a similar function for rotation on the Z axis (i.e. on the XY plane), setting or snapping to half-sextant intervals (1/12 of a circle).

I need to do a bit more documentation and decide how I want to organize the folders now that there are MonoBehaviors in the package, but everything is implemented and tested. I should be submitting it within the next 24 hours, and I’ll post the complete change log once I do.

The latest HexKit update is live on the Asset Store.

Editor integration has started creeping into HexKit! Version 1.2 introduces the HexLocation and HexFacing behavior scripts. When attached to an object, these provide editor facilities for hex grid placement and rotation. HexLocation can be used with snapping turned off to track the HexCoord location of an object as it moves through real space. HexFacing has five operation modes, selected from a drop-down in the editor (an enumeration script-side), allowing it to fit every usage I could imagine for it, including some specifically intended for sprites. A dedicated sprite behavior, which understands things like mirroring, is planned as a future counterpart to HexFacing.

A new version of Radiate() has been added, allowing partial shadows! It can be used for some nice lighting effects, but it can serve to model anything diminished by interposing objects: sound levels, heat or explosions that might be partially absorbed, etc. The original Radiate() has been redesigned for consistency, changing both its method signature and the format of the delegate function it uses. Conveniently, this means that the old Radiate() could be kept around and will keep working with no changes to existing code.

The last big news is that Unity 4.5.0 has made HexCoordinate completely obsolete. Like the old Radiate(), it’s still in the package to avoid breaking anything, but it’s buried in a deep subfolder to minimize confusion. HexCoord is now serializable, and public HexCoord fields can be edited directly from the Unity Inspector, preserving their data in prefabs etc.

And as usual, HexCoord got a few new functions too. Here’s the full changelog:

 == GENERAL ==
Documentation:
- Added ELI5 for Behaviors vs. Logic.
- Updated to reflect all user-visible changes and additions.

Folder Structure:
- Moved existing classes, as well as the Internal folder, to a new Logic folder.
- Added a Behaviors folder for the new MonoBehavior additions.

 == BEHAVIORS ==

HexLocation: (new)
- Enables grid-snapping in the editor.
- Can also be used to find location on a grid, without snapping.

HexFacing: (new)
- Constrains rotation to hex-grid cardinals and diagonals in or out of editor.
- Several constraint modes (and some non-constraining) are provided, intended to work well with sprites.

 == LOGIC ==

HexCoord:
- Added PolarNeighbor(), gets next/previous hex in same ring from origin, faster than static AtPolar()
- Added AngleToHalfSextant(), HalfSextantToAngle()
- Improved behavior of CartesianBoundingRectangle(), bounds were unnecessarily large in some cases.
- Unity 4.5.0 can serialize structs! HexCoord is now serializable.
- Readonly fields aren't exposed to the Inspector, so HexCoord is no longer immutable.
- Updated Scale() to modify in-place. (Still returns, to avoid code breakage.)

HexCoordinate:
- Obsolete. Still in the package (again, avoid breakage) but moved to a Deprecated folder inside Internal Classes.

HexKit:
- Added a variant Radiate which allows partial transparency (arbitrary integer, like MoveCost pathfinding).
- Binary Radiate() changed to provide consistent API and feature set.
- Method signature change allowed old binary Radiate() to remain, but it is deprecated.

HexRayHit: (new)
- Abstract decorator class for variable-transparency Radiate(), used like HexPathNode.

I’m currently in the process of packing up for relocation from Pacific to Atlantic. I’m not actually gone for another week, but my attention is focused on the move. I’m going to try to post a teaser of something from the next version before I go dark on the 12th, but I can’t promise it’ll happen. If anyone has found an actual bug, please let me know ASAP and I’ll try to patch it before I go.

After that, I’ll be mostly offline for about a week, then limited for another month while living in temporary shared lodging. This will slow development and limit my responsiveness, so I’d like to apologize in advance. Things should be back to normal before August!

SNAFU with the cable company and my net’s out three days early, so I’m functionally offline as of now.

Phase 1 of the move is complete! Still busy, but I’m online and responsive.

Once more, I’d like to thank everyone who has given HexKit a try. I’d love to hear any stories about how it’s been used thus far – even basic prototype and feature-exploration stuff, because I’m sure the documentation could be improved – and again I encourage any and all feature requests!

I have a few questions before trying this one.

  1. Each node is an object? Im asking because my grid can be big (now I have a ~130width x75height) and having objects is not an option. If its not an object, how can I find which object I click?

  2. The pathfind system, how it works? Ideally, I should pass the start and the end node/grid position and the system returns me a list of nodes/grid positions. Then I can take care of animation.

  3. Is it possible, in any way to save all grid information? I mean, I run the (compiled) project, “buid” the path somehow, save it somehow (xml, text, whatever), then I load that info back to unity editor.

  1. Everything is done with HexCoord structs, which are defined by two integers and can convert to and from to Unity positions. You can use a single object for your grid, and get coordinates based on where you clicked relative to the object’s center – a similar method is used in the sample code, based on screen location instead of a background object. Then, you can map coordinates back to your active game objects with a dictionary or other central list. Or, you can detect clicks on your active objects, and convert their positions to HexCoord to find where they are on the grid.

  2. You write a function that says whether or not a node is legal, and give that function to the pathfinder along with your start and end nodes. It returns an array of HexCoord containing the path.

  3. There’s no built-in function for it, but Unity’s serialization can handle structs with version 4.5+. The easiest way would be to save the path info in a public variable, or one marked with [SerializeField].

Edit: To be 100% clear, HexCoord is not an object but a struct. This means there is no instantiation cost, it exists only on the stack unless saved to a field in another object. It encodes only location, no other node information – nodes aren’t defined at all, that’s why pathfinding requires a helper function. It lets you organize your data however you need to.