Skip to content


Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Hexagonal Map Coordinates Helper

Red Blob Games Websiteで 説明されている立方体座標・QR座標のC#での実装
This C# code implements Cube- and QR-based coordinates described in Red Blob Games Website.



There are 2 coordinates supported - Cube and QR(Axial.)
Constructors of those value objects are private, and you must make through specific methods, fromCube and fromQR respectively.

The supported coordinates makes creating concentric hexagonal map easy. Better supports for map that spreads in the form of a rectaingle are planned through offset coordinates.

Note that whether your hexagonal map is pointy-topped or flat-topped is completely up to you. These coordinates should work fine under both circumstances.

Also note that you MUST NOT directly change the value for the coordinates. You can't. If you want to modify the value and save it somewhere else, just create new coordinate object with modified value.

Cube Coordinates

Let's take a cube grid and slice out a diagonal plane at x + y + z = 0. This is a weird idea but it helps us make hex grid algorithms simpler. In particular, we can reuse standard operations from cartesian coordinates: adding coordinates, subtracting coordinates, multiplying or dividing by a scalar, and distances.
- Red Blob Games

Use HexagonalMap.Domain.HexMap.CubeCoordinate to represent the cube coordinates.

// The center
var center = CubeCoordinate.fromCube(0,0,0);
// Top hexagon (in flat-top system)
var top = CubeCoordinate.fromCube(0,1,-1);
// You can access each coordinate via:
top.x // -> 0
top.y // -> 1
top.z // -> -1
// Note that in Cube coordinate, x + y + z is always 0. If they aren't, it will yield an exception.
var fail = CubeCoordinate.fromCube(1,2,3); // -> ArgumentException

Addition and Deduction are implemented. This is important when finding the 6 neighbours.

// CubeCoordinates has a method to return a list of relative positions
// of the 6 neighbours. 
var relativeNeighbours = CubeCoordinate.AdjacentRelatives();
var origin = CubeCoordinate.fromCube(0,0,0);
foreach (var relative in relativeNeighbours) {
    origin + relative // -> is the coordinate for one of the neighbour of origin.

Find if two coordinate match simply using == (or don't match using !=)

var a = CubeCoordinate.fromCube(0,0,0);
var b = CubeCoordinate.fromCube(0,0,0);
var c = CubeCoordinate.fromCube(1,0,-1);

a == b // -> true
a != b // -> false
a == c // -> false
a != c // -> true

QR Coordinates (Axial Coordinates)

The axial coordinate system, sometimes called “trapezoidal” or “oblique” or “skewed”, is built by taking two of the three coordinates from a cube coordinate system.
- Red Blob Games

This coordinate is extremely useful for drawing, since you can convert the hexagons' position with little math.

Use HexagonalMap.Domain.HexMap.QRCoordinate to represent the QR coordinates.

// The center
var center = QRCoordinate.fromQR(0,0);
// Top hexagon (in flat-top system)
var top = QRCoordinate.fromQR(0, -1);
// Get values of each coordinate
top.q // -> 0
top.r // -> -1

QRCoordinates cannot give you the relative coordinate of 6 neighbours, but addition, deduction, equality checks are implemented. See Cube Coordinates for usage.

Converting Coordinates

Cube Coordinates and QR Coordinates can be converted into each other. Simply call:

var qr = QRCoordinate.fromQR(0,0);
var cube = CubeCoordinate.fromCube(0,0,0);
QRCoordinate.fromCube(cube); // -> returns a QR coordinate for the given Cube coordinate
CubeCoordinate.fromQR(qr); // -> returns a Cube coordinate for the given QR coordinate
qr.toCube(); // -> converts itself (QR) into Cube coordinate
cube.toQR(); // -> converts itself (Cube) into QR coordinate

You can also directly create those coordinates with values for other system:

var qr = QRCoordinate.fromCube(0,0,0); // -> is a QR coordinate that is equal to Cube coordinate (0,0,0)
var cube = CubeCoordinate.fromQR(0,0); // -> is a Cube coordinate that is equal to QR coordinate (0,0)

Field and Cells


If any of your object in your games needs to know its hexagonal position, inherit HexagonalMap.Domain.HexMap.Cell.
To initialize its position, call initPosition(). Get its position through Position parameter.

public class Block: Cell
    public int Score { get; set; }


HexagonalMap.Domain.HexMap.Field can hold objects inheriting Cell.

If you need a hexagonal field, inherit Field to your class.
This will help you finding cells in your game fields.

Here are few things to remember:

  1. You need to add your Cells into the field before the field can find them.
var map = new Map(5);
var block = new Block(CubeCoordinate.fromCube(0,0,0), 50);
  1. Since you shouldn't change your Cells position directly, if you want cells to move to another place, you need to remove it from the map, create new Cell with different location, and add it back to the Field.
  2. Field cannot have more than 1 cell at the same spot. Forcing so will get you an ArgumentException. You can use it to detect collision, if you like.
// Moving a cell at the center...
// Remove it from the field first. RemoveCellAt gives you the removed cell.
var removedCell = map.RemoveCellAt(CubeCoordinate.fromCube(0,0,0));
// Recreate your cell data with the new location
var movedCell = new Block(CubeCoordinate.fromCube(1,0,-1), block.Score);
// Adding back might yield exception. If it does, resolve the situation first.
try {
catch (ArgumentException e)
    // Collision! It might be that your cell bumped into an enemy.

Inheriting Field grants you following benefits:

  1. You can find a cell at a given coordinate.
var foundByCube = map.FindCellAt(CubeCoordinate.fromCube(0,0,0));
var foundByQR = map.FindCellAt(QRCoordinate.fromQR(0,0));
  1. You can find the 6 neighboring cells (if it exists on the Field.)
map.FindNeighborsOf(foundByCube); // -> returns list of cells up to 6.

Glitchy behaviors?

Open the issue in this repository! If you provide some reproducable codes, things will go smoother!


Hexagonal map and cells data structure helper based on







No releases published


No packages published