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.
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
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.
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)
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:
- You need to add your
Cell
s into the field before the field can find them.
var map = new Map(5);
var block = new Block(CubeCoordinate.fromCube(0,0,0), 50);
map.AddCell(block);
- Since you shouldn't change your
Cell
s position directly, if you want cells to move to another place, you need to remove it from the map, create newCell
with different location, and add it back to theField
. Field
cannot have more than 1 cell at the same spot. Forcing so will get you anArgumentException
. 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 {
map.AddCell(movedCell);
}
catch (ArgumentException e)
{
// Collision! It might be that your cell bumped into an enemy.
}
Inheriting Field
grants you following benefits:
- 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));
- You can find the 6 neighboring cells (if it exists on the
Field
.)
map.FindNeighborsOf(foundByCube); // -> returns list of cells up to 6.
Open the issue in this repository! If you provide some reproducable codes, things will go smoother!