From c28d7ba8eb8c51f5942270beee323f576b63c9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Wed, 21 Mar 2018 23:09:26 +0100 Subject: [PATCH] Started work on arena grid --- src/core/ArenaGrid.spec.ts | 29 +++++++++++++++++++++++++++++ src/core/ArenaGrid.ts | 34 ++++++++++++++++++++++++++++++++++ src/core/Battle.ts | 5 +++++ src/core/Target.ts | 12 ++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 src/core/ArenaGrid.spec.ts create mode 100644 src/core/ArenaGrid.ts diff --git a/src/core/ArenaGrid.spec.ts b/src/core/ArenaGrid.spec.ts new file mode 100644 index 0000000..c2cd018 --- /dev/null +++ b/src/core/ArenaGrid.spec.ts @@ -0,0 +1,29 @@ +module TK.SpaceTac.Specs { + function checkLocation(check: TestContext, got: IArenaLocation, expected_x: number, expected_y: number) { + check.equals(got.x, expected_x, `x differs (${got.x},${got.y}) (${expected_x},${expected_y})`); + check.equals(got.y, expected_y, `y differs (${got.x},${got.y}) (${expected_x},${expected_y})`); + } + + testing("HexagonalArenaGrid", test => { + test.case("snaps coordinates to the nearest grid point, on a biased grid", check => { + let grid = new HexagonalArenaGrid(4, 0.75); + checkLocation(check, grid.snap({ x: 0, y: 0 }), 0, 0); + checkLocation(check, grid.snap({ x: 1, y: 0 }), 0, 0); + checkLocation(check, grid.snap({ x: 1.9, y: 0 }), 0, 0); + checkLocation(check, grid.snap({ x: 2.1, y: 0 }), 4, 0); + checkLocation(check, grid.snap({ x: 1, y: 1 }), 0, 0); + checkLocation(check, grid.snap({ x: 1, y: 2 }), 2, 3); + checkLocation(check, grid.snap({ x: -1, y: -1 }), 0, 0); + checkLocation(check, grid.snap({ x: -2, y: -2 }), -2, -3); + checkLocation(check, grid.snap({ x: -3, y: -1 }), -4, 0); + checkLocation(check, grid.snap({ x: 6, y: -5 }), 8, -6); + }); + + test.case("snaps coordinates to the nearest grid point, on a regular grid", check => { + let grid = new HexagonalArenaGrid(10); + checkLocation(check, grid.snap({ x: 0, y: 0 }), 0, 0); + checkLocation(check, grid.snap({ x: 8, y: 0 }), 10, 0); + checkLocation(check, grid.snap({ x: 1, y: 6 }), 5, 10 * Math.sqrt(0.75)); + }); + }); +} diff --git a/src/core/ArenaGrid.ts b/src/core/ArenaGrid.ts new file mode 100644 index 0000000..b9a6aef --- /dev/null +++ b/src/core/ArenaGrid.ts @@ -0,0 +1,34 @@ +module TK.SpaceTac { + /** + * Abstract grid for the arena where the battle takes place + * + * The grid is used to snap arena coordinates for ships and targets + */ + export interface IArenaGrid { + snap(loc: IArenaLocation): IArenaLocation; + } + + /** + * 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 implements IArenaGrid { + private yunit: number; + + constructor(private unit: number, private yfactor = Math.sqrt(0.75)) { + 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); + } + } +} diff --git a/src/core/Battle.ts b/src/core/Battle.ts index 9db587e..f095b4c 100644 --- a/src/core/Battle.ts +++ b/src/core/Battle.ts @@ -3,6 +3,9 @@ module TK.SpaceTac { * A turn-based battle between fleets */ export class Battle { + // Grid for the arena + grid?: IArenaGrid + // Battle outcome, if the battle has ended outcome: BattleOutcome | null = null @@ -38,6 +41,8 @@ module TK.SpaceTac { ai_playing = false constructor(fleet1 = new Fleet(new Player("Attacker")), fleet2 = new Fleet(new Player("Defender")), width = 1808, height = 948) { + this.grid = new HexagonalArenaGrid(50); + this.fleets = [fleet1, fleet2]; this.ships = new RObjectContainer(fleet1.ships.concat(fleet2.ships)); this.play_order = []; diff --git a/src/core/Target.ts b/src/core/Target.ts index f029ce6..75a12ba 100644 --- a/src/core/Target.ts +++ b/src/core/Target.ts @@ -64,6 +64,18 @@ module TK.SpaceTac { return new Target(x, y, null); } + /** + * Snap to battle grid + */ + snap(grid: IArenaGrid): Target { + if (this.ship_id) { + return this; + } else { + let location = grid.snap(this); + return Target.newFromLocation(location.x, location.y); + } + } + // Get distance to another target getDistanceTo(other: { x: number, y: number }): number { var dx = other.x - this.x;