bourgade/src/hexgrid.ts

136 lines
3.6 KiB
TypeScript

/**
* A class representing coordinates in a hexagonal grid with 2 dimensions.
* Offset system is "odd-r".
*/
export class Hex {
x: number;
y: number;
constructor(x: number | { x: number, y: number }, y?: number) {
if (typeof x === "number") {
this.x = x as number;
this.y = y || 0;
}
else {
this.x = x.x;
this.y = x.y;
}
}
toCube() {
const q = this.x - (this.y - (this.y&1)) / 2;
const r = this.y;
return new Cube(q, r, -q - r);
}
}
/**
* A class representing coordinates in a hexagonal grid with 3 dimensions.
* Mostly used as a transient value for easier algorithms.
*/
class Cube {
q: number;
r: number;
s: number;
constructor(q: number, r: number, s: number) {
this.q = q;
this.r = r;
this.s = s;
}
toHex() {
return new Hex(
this.q + (this.r - (this.r&1)) / 2,
this.r
);
}
add(cube: Cube) {
return new Cube(this.q + cube.q, this.r + cube.r, this.s + cube.s);
}
subtract(cube: Cube) {
return new Cube(this.q - cube.q, this.r - cube.r, this.s - cube.s);
}
}
export function getCornersAtDistance(distance: number) {
const results: Hex[] = [];
for (let q = -distance; q <= distance; q++) {
for (let r = Math.max(-distance, -q - distance); r <= Math.min(distance, -q + distance); r++) {
const s = -q - r;
if (
(q === 0 || r === 0 || s === 0)
&& Math.max(Math.abs(q), Math.abs(r), Math.abs(s)) === distance
) {
const cube = new Cube(q, r, s);
results.push(cube.toHex());
}
}
}
return results;
}
export function getTilesAtDistance(distance: number) {
const results: Hex[] = [];
for (let q = -distance; q <= distance; q++) {
for (let r = Math.max(-distance, -q - distance); r <= Math.min(distance, -q + distance); r++) {
const s = -q - r;
if (Math.max(Math.abs(q), Math.abs(r), Math.abs(s)) === distance) {
const cube = new Cube(q, r, s);
results.push(cube.toHex());
}
}
}
return results;
}
const adjacentVectors = [
new Cube(+1, 0, -1), new Cube(+1, -1, 0), new Cube(0, -1, +1),
new Cube(-1, 0, +1), new Cube(-1, +1, 0), new Cube(0, +1, -1),
];
/**
* Return all coordinates adjacent to a given one.
* @param tile Hex - 2D coordinates in a hexagonal grid.
* @returns Array of 6 2D coordinates.
*/
export function getAdjacentCoords(tile: Hex): Hex[] {
const origin = tile.toCube();
return adjacentVectors.map(vec => origin.add(vec).toHex());
}
/**
* Return a position on the 3D board based on coordinates of a tile on our grid.
* @param x The x coordinate in the grid.
* @param y The y coordinate in the grid.
* @returns An array containing the 3 coordinates (x, y, z) of that tile on a 3D board.
*/
export function getPositionOnBoard(x: number, y: number): [number, number, number] {
const posX = x * 2 + (y % 2 ? 1 : 0);
const posY = 0;
const posZ = y * 1.72;
return [ posX, posY, posZ ];
}
/**
* Return the distance between two cells.
* @param a Hex - 2D coordinates in a hexagonal grid.
* @param b Hex - 2D coordinates in a hexagonal grid.
* @returns Distance between the two coordinates.
*/
export function distanceBetween(a: Hex, b: Hex): number {
const aCube = a.toCube();
const bCube = b.toCube();
const vector = aCube.subtract(bCube);
return (Math.abs(vector.q) + Math.abs(vector.r) + Math.abs(vector.s)) / 2;
}