136 lines
3.6 KiB
TypeScript
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;
|
|
}
|