1
0
Fork 0
spacetac/src/core/ArenaGrid.ts
2018-07-10 16:23:32 +02:00

105 lines
3 KiB
TypeScript

module TK.SpaceTac {
/**
* Abstract grid for the arena where the battle takes place
*
* The grid is used to snap arena coordinates on grid vertices, for ships and targets
*
* The default implementation does not enforce any grid or unit (leaves coordinates as they are)
*/
export class ArenaGrid {
/**
* Get the base unit of measurement between two points
*/
getUnit(): number {
return 1;
}
/**
* Check that an arena location is on a grid vertex
*/
check(loc: IArenaLocation): boolean {
return arenaDistance(loc, this.snap(loc)) < 1e-8;
}
/**
* Snap a floating point arena location to a grid vertex
*/
snap(loc: IArenaLocation): IArenaLocation {
return loc;
}
/**
* Measure the distance between two points
*
* This returns a distance in grid units
*/
measure(loc1: IArenaLocation, loc2: IArenaLocation): number {
return arenaDistance(this.snap(loc1), this.snap(loc2));
}
/**
* Check that a location is in range of another
*/
inRange(loc1: IArenaLocation, loc2: IArenaLocation, range: number): boolean {
return this.measure(loc1, loc2) - range < 1e-8;
}
}
/**
* Pixel unbounded grid
*
* This will only round the coordinates to the pixels, with an optional unit for distance measurements
*/
export class PixelGrid extends ArenaGrid {
constructor(protected readonly unit = 1) {
super();
}
getUnit(): number {
return this.unit;
}
snap(loc: IArenaLocation): IArenaLocation {
return new ArenaLocation(Math.round(loc.x), Math.round(loc.y));
}
measure(loc1: IArenaLocation, loc2: IArenaLocation): number {
let d = super.measure(loc1, loc2) / this.unit;
let r = Math.round(d);
if (r >= d) {
return Math.floor(d);
} else if (r - d < 1e-8) {
return r;
} else {
return Math.ceil(d);
}
}
}
/**
* Hexagonal unbounded arena grid
*
* This grid is composed of regular hexagons where all vertices are at a same distance "unit" of the hexagon center
*/
export class HexagonalArenaGrid extends PixelGrid {
private readonly yunit: number;
constructor(unit: number, yfactor = Math.sqrt(0.75)) {
super(unit);
this.yunit = unit * yfactor;
}
snap(loc: IArenaLocation): IArenaLocation {
let yr = Math.round(loc.y / this.yunit);
let xr: number;
if (yr % 2 == 0) {
xr = Math.round(loc.x / this.unit);
} else {
xr = Math.round((loc.x - 0.5 * this.unit) / this.unit) + 0.5;
}
return new ArenaLocation((xr * this.unit) || 0, (yr * this.yunit) || 0);
}
}
}