@xtia/grid 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -130,6 +130,21 @@ const mountainCells = world.cells.toFlatArrayXY()
130
130
  .filter(cell => cell.value === "mountain")
131
131
  .map(cell => [cell.x, cell.y]);
132
132
 
133
+ // or get a live, renderable minimap
134
+ import { C } from "@xtia/rgba";
135
+
136
+ const colourMap = new Map(Object.entries({
137
+ grass: C.x0f0,
138
+ water: C.x00f,
139
+ forest: C.x080,
140
+ mountain: C.xa70
141
+ }));
142
+ const minimap = world.pipe
143
+ .map(colourMap)
144
+ .floorCoordinates()
145
+ .crop(viewX, viewY, vw, vh)
146
+ .stretch(canvas.width, canvas.height);
147
+
133
148
  ```
134
149
 
135
150
  ## Cell interface
@@ -190,7 +205,7 @@ const visibility = start.createVisibilityMap(
190
205
 
191
206
  // any 2d source, including visibility maps, can be used as a mask for paste/fill operations
192
207
  // paste(source: Source2D<T>, mask?: Source2D<boolean>)
193
- screenGrid.paste(spriteMap, visibility);
208
+ screenGrid.paste(spriteMap, 0, 0, visibility);
194
209
  ```
195
210
 
196
211
  ### Reusing path data
package/lib/grid.d.ts CHANGED
@@ -13,7 +13,7 @@ type PathFindOptions<T> = {
13
13
  cell: Cell<T>;
14
14
  cost: number;
15
15
  }) => void;
16
- shortcutMap?: Source2D<Cell<T>[] | undefined> | GetXYFunc<Cell<T>[]>;
16
+ shortcutMap?: Source2D<LocationSpec<T>[] | undefined> | GetXYFunc<LocationSpec<T>[] | undefined>;
17
17
  };
18
18
  type CostMapOptions<T> = PathFindOptions<T> & {
19
19
  stopAt?: LocationSpec<T>;
@@ -65,7 +65,7 @@ export declare class Grid<T> {
65
65
  set(x: number, y: number, value: T): void;
66
66
  trySet(x: number, y: number, value: T): boolean;
67
67
  fill(value: T, mask?: Source2D<boolean> | GetXYFunc<boolean>): void;
68
- paste(x: number, y: number, source: Source2D<T>, mask?: Source2D<boolean> | GetXYFunc<boolean>): void;
68
+ paste(source: Source2D<T>, x?: number, y?: number, mask?: Source2D<boolean> | GetXYFunc<boolean>): void;
69
69
  [Symbol.iterator](): IterableIterator<{
70
70
  x: number;
71
71
  y: number;
package/lib/grid.js CHANGED
@@ -50,11 +50,7 @@ export class Cell {
50
50
  return this.gridView.cells.get(xDelta + this.x, yDelta + this.y);
51
51
  }
52
52
  findPath(target, getCost, options = {}) {
53
- const pathMap = this.calculateCosts(getCost, {
54
- stopAt: target,
55
- allowDiagonal: options.allowDiagonal,
56
- maxCost: options.maxCost,
57
- }, true);
53
+ const pathMap = this.calculateCosts(getCost, Object.assign(Object.assign({}, options), { stopAt: target }), true);
58
54
  return pathMap === null || pathMap === void 0 ? void 0 : pathMap.get(...this.getSiblingXY(target));
59
55
  }
60
56
  getPathMap(getCost, options = {}) {
@@ -98,7 +94,7 @@ export class Cell {
98
94
  ? options.shortcutMap(current.x, current.y)
99
95
  : (_b = options.shortcutMap) === null || _b === void 0 ? void 0 : _b.get(current.x, current.y);
100
96
  if (shortcutCells) {
101
- const shortcuts = shortcutCells.map(cell => ({
97
+ const shortcuts = shortcutCells.map(loc => this.getSiblingCell(loc)).map(cell => ({
102
98
  traversalType: TraversalType.shortcut,
103
99
  cell
104
100
  }));
@@ -185,14 +181,14 @@ export class Cell {
185
181
  }
186
182
  }
187
183
  createVisibilityMap(isClear, options = {}) {
188
- var _a, _b;
189
- const maxDistance = (_a = options.maxDistance) !== null && _a !== void 0 ? _a : Infinity;
190
- const boundariesVisible = (_b = options.boundariesVisible) !== null && _b !== void 0 ? _b : true;
184
+ var _a;
185
+ const maxDistance = options.maxDistance;
186
+ const boundariesVisible = (_a = options.boundariesVisible) !== null && _a !== void 0 ? _a : true;
191
187
  return new Pipe2D(this.gridView.width, this.gridView.height, (x, y) => {
192
188
  if (!isClear(this)) {
193
189
  return x === this.x && y === this.y ? boundariesVisible : false;
194
190
  }
195
- if (maxDistance < Infinity) {
191
+ if (maxDistance !== undefined) {
196
192
  if (getDistance(this, { x, y }) > maxDistance) {
197
193
  return false;
198
194
  }
@@ -239,7 +235,12 @@ export class Grid {
239
235
  this.parentSet(x, y, value);
240
236
  }
241
237
  trySet(x, y, value) {
242
- if (x < 0 || x >= this.width || y < 0 || y >= this.height)
238
+ if (x < 0
239
+ || x >= this.width
240
+ || y < 0
241
+ || y >= this.height
242
+ || !Number.isInteger(x)
243
+ || !Number.isInteger(y))
243
244
  return false;
244
245
  this.set(x, y, value);
245
246
  return true;
@@ -260,7 +261,7 @@ export class Grid {
260
261
  }
261
262
  });
262
263
  }
263
- paste(x, y, source, mask) {
264
+ paste(source, x = 0, y = 0, mask) {
264
265
  const maskSource = typeof mask == "function" ? {
265
266
  width: this.width,
266
267
  height: this.height,
@@ -311,8 +312,6 @@ export class Grid {
311
312
  return new Grid(width, height, (tx, ty) => {
312
313
  return this.parentGet(tx + x, ty + y);
313
314
  }, (tx, ty, value) => {
314
- if (tx < 0 || ty < 0 || tx >= width || ty >= height)
315
- throw new Error("Out of bounds");
316
315
  this.parentSet(tx + x, ty + y, value);
317
316
  }, fn => this.batch(fn));
318
317
  }
@@ -381,17 +380,20 @@ export class GridBase extends Grid {
381
380
  if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
382
381
  throw new Error(`Coordinates out of bounds: (${x}, ${y})`);
383
382
  }
383
+ if (!Number.isInteger(x) || !Number.isInteger(y)) {
384
+ throw new Error(`Coordinates must be integer; got (${x}, ${y})`);
385
+ }
384
386
  return y * this.width + x;
385
387
  }
386
388
  _set(x, y, value) {
387
389
  const idx = this.xyToIndex(x, y);
388
390
  if (this.data[idx] === value)
389
391
  return;
392
+ this.data[this.xyToIndex(x, y)] = value;
390
393
  if (this.batchState) {
391
394
  this.batchState.changedCells.add(this.cells.get(x, y));
392
395
  return;
393
396
  }
394
- this.data[this.xyToIndex(x, y)] = value;
395
397
  if (this.eventHandlers.change) {
396
398
  this.triggerChange(new Set([this.cells.get(x, y)]));
397
399
  }
package/lib/utils.d.ts CHANGED
@@ -4,14 +4,6 @@ export type Source2D<T> = {
4
4
  height: number;
5
5
  get: GetXYFunc<T>;
6
6
  };
7
- export type Angle = {
8
- asDegrees: number;
9
- } | {
10
- asRadians: number;
11
- } | {
12
- asTurns: number;
13
- };
14
- export declare function angleToRadians(angle: Angle): number;
15
7
  export declare class OrderedQueue<T> {
16
8
  private getCost;
17
9
  private queue;
package/lib/utils.js CHANGED
@@ -1,12 +1,3 @@
1
- export function angleToRadians(angle) {
2
- if ("asRadians" in angle)
3
- return angle.asRadians;
4
- if ("asDegrees" in angle)
5
- return angle.asDegrees * (180 / Math.PI);
6
- if ("asTurns" in angle)
7
- return angle.asTurns * Math.PI * 2;
8
- throw new Error("Invalid angle");
9
- }
10
1
  export class OrderedQueue {
11
2
  constructor(getCost, ...values) {
12
3
  this.getCost = getCost;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.9",
2
+ "version": "0.0.10",
3
3
  "description": "2D store and utilities, with zero-copy regions and transform layers, pathfinding, Pipe2D interop",
4
4
  "name": "@xtia/grid",
5
5
  "exports": {
@@ -9,7 +9,12 @@
9
9
  },
10
10
  "./lib/*": null
11
11
  },
12
- "keywords": ["grid", "game-dev", "pathfinding", "cellular-automata"],
12
+ "keywords": [
13
+ "grid",
14
+ "game-dev",
15
+ "pathfinding",
16
+ "cellular-automata"
17
+ ],
13
18
  "scripts": {
14
19
  "build": "npx tsc",
15
20
  "test": "npx vitest run"
@@ -18,10 +23,11 @@
18
23
  "lib/"
19
24
  ],
20
25
  "devDependencies": {
26
+ "@vitest/coverage-v8": "^4.1.10",
21
27
  "typescript": "^7.0.2",
22
28
  "vitest": "^4.1.10"
23
29
  },
24
30
  "dependencies": {
25
- "@xtia/pipe2d": "^2.1.0"
31
+ "@xtia/pipe2d": "^2.2.1"
26
32
  }
27
33
  }