@lagless/2d-map-generator 0.0.48

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.
Files changed (124) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +373 -0
  3. package/dist/index.d.ts +31 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +27 -0
  6. package/dist/lib/collision/rapier-provider.d.ts +54 -0
  7. package/dist/lib/collision/rapier-provider.d.ts.map +1 -0
  8. package/dist/lib/collision/rapier-provider.js +67 -0
  9. package/dist/lib/collision/spatial-grid-provider.d.ts +19 -0
  10. package/dist/lib/collision/spatial-grid-provider.d.ts.map +1 -0
  11. package/dist/lib/collision/spatial-grid-provider.js +127 -0
  12. package/dist/lib/core/generated-map.d.ts +14 -0
  13. package/dist/lib/core/generated-map.d.ts.map +1 -0
  14. package/dist/lib/core/generated-map.js +17 -0
  15. package/dist/lib/core/map-dimensions.d.ts +8 -0
  16. package/dist/lib/core/map-dimensions.d.ts.map +1 -0
  17. package/dist/lib/core/map-dimensions.js +7 -0
  18. package/dist/lib/core/map-generator.d.ts +14 -0
  19. package/dist/lib/core/map-generator.d.ts.map +1 -0
  20. package/dist/lib/core/map-generator.js +124 -0
  21. package/dist/lib/core/terrain-query.d.ts +17 -0
  22. package/dist/lib/core/terrain-query.d.ts.map +1 -0
  23. package/dist/lib/core/terrain-query.js +54 -0
  24. package/dist/lib/features/biome-feature.d.ts +10 -0
  25. package/dist/lib/features/biome-feature.d.ts.map +1 -0
  26. package/dist/lib/features/biome-feature.js +9 -0
  27. package/dist/lib/features/bridge-feature.d.ts +10 -0
  28. package/dist/lib/features/bridge-feature.d.ts.map +1 -0
  29. package/dist/lib/features/bridge-feature.js +55 -0
  30. package/dist/lib/features/grass-feature.d.ts +10 -0
  31. package/dist/lib/features/grass-feature.d.ts.map +1 -0
  32. package/dist/lib/features/grass-feature.js +36 -0
  33. package/dist/lib/features/ground-patch-feature.d.ts +10 -0
  34. package/dist/lib/features/ground-patch-feature.d.ts.map +1 -0
  35. package/dist/lib/features/ground-patch-feature.js +57 -0
  36. package/dist/lib/features/lake-feature.d.ts +10 -0
  37. package/dist/lib/features/lake-feature.d.ts.map +1 -0
  38. package/dist/lib/features/lake-feature.js +65 -0
  39. package/dist/lib/features/object-placement-feature.d.ts +18 -0
  40. package/dist/lib/features/object-placement-feature.d.ts.map +1 -0
  41. package/dist/lib/features/object-placement-feature.js +229 -0
  42. package/dist/lib/features/places-feature.d.ts +10 -0
  43. package/dist/lib/features/places-feature.d.ts.map +1 -0
  44. package/dist/lib/features/places-feature.js +14 -0
  45. package/dist/lib/features/river-feature.d.ts +10 -0
  46. package/dist/lib/features/river-feature.d.ts.map +1 -0
  47. package/dist/lib/features/river-feature.js +122 -0
  48. package/dist/lib/features/shore-feature.d.ts +10 -0
  49. package/dist/lib/features/shore-feature.d.ts.map +1 -0
  50. package/dist/lib/features/shore-feature.js +20 -0
  51. package/dist/lib/math/catmull-rom.d.ts +12 -0
  52. package/dist/lib/math/catmull-rom.d.ts.map +1 -0
  53. package/dist/lib/math/catmull-rom.js +42 -0
  54. package/dist/lib/math/collision-test.d.ts +14 -0
  55. package/dist/lib/math/collision-test.d.ts.map +1 -0
  56. package/dist/lib/math/collision-test.js +29 -0
  57. package/dist/lib/math/jagged-aabb.d.ts +12 -0
  58. package/dist/lib/math/jagged-aabb.d.ts.map +1 -0
  59. package/dist/lib/math/jagged-aabb.js +47 -0
  60. package/dist/lib/math/polygon-utils.d.ts +19 -0
  61. package/dist/lib/math/polygon-utils.d.ts.map +1 -0
  62. package/dist/lib/math/polygon-utils.js +79 -0
  63. package/dist/lib/math/river-polygon.d.ts +12 -0
  64. package/dist/lib/math/river-polygon.d.ts.map +1 -0
  65. package/dist/lib/math/river-polygon.js +84 -0
  66. package/dist/lib/math/spline.d.ts +15 -0
  67. package/dist/lib/math/spline.d.ts.map +1 -0
  68. package/dist/lib/math/spline.js +127 -0
  69. package/dist/lib/physics/canopy-sensor-tag.d.ts +2 -0
  70. package/dist/lib/physics/canopy-sensor-tag.d.ts.map +1 -0
  71. package/dist/lib/physics/canopy-sensor-tag.js +1 -0
  72. package/dist/lib/physics/create-map-colliders.d.ts +12 -0
  73. package/dist/lib/physics/create-map-colliders.d.ts.map +1 -0
  74. package/dist/lib/physics/create-map-colliders.js +29 -0
  75. package/dist/lib/presets/standard-biome.d.ts +3 -0
  76. package/dist/lib/presets/standard-biome.d.ts.map +1 -0
  77. package/dist/lib/presets/standard-biome.js +9 -0
  78. package/dist/lib/presets/standard-map.d.ts +6 -0
  79. package/dist/lib/presets/standard-map.d.ts.map +1 -0
  80. package/dist/lib/presets/standard-map.js +61 -0
  81. package/dist/lib/presets/standard-objects.d.ts +6 -0
  82. package/dist/lib/presets/standard-objects.d.ts.map +1 -0
  83. package/dist/lib/presets/standard-objects.js +25 -0
  84. package/dist/lib/types/collision-provider.d.ts +8 -0
  85. package/dist/lib/types/collision-provider.d.ts.map +1 -0
  86. package/dist/lib/types/collision-provider.js +1 -0
  87. package/dist/lib/types/feature-configs.d.ts +139 -0
  88. package/dist/lib/types/feature-configs.d.ts.map +1 -0
  89. package/dist/lib/types/feature-configs.js +8 -0
  90. package/dist/lib/types/feature.d.ts +31 -0
  91. package/dist/lib/types/feature.d.ts.map +1 -0
  92. package/dist/lib/types/feature.js +12 -0
  93. package/dist/lib/types/generated-map.d.ts +10 -0
  94. package/dist/lib/types/generated-map.d.ts.map +1 -0
  95. package/dist/lib/types/generated-map.js +1 -0
  96. package/dist/lib/types/generated-river.d.ts +23 -0
  97. package/dist/lib/types/generated-river.d.ts.map +1 -0
  98. package/dist/lib/types/generated-river.js +1 -0
  99. package/dist/lib/types/geometry.d.ts +30 -0
  100. package/dist/lib/types/geometry.d.ts.map +1 -0
  101. package/dist/lib/types/geometry.js +5 -0
  102. package/dist/lib/types/index.d.ts +16 -0
  103. package/dist/lib/types/index.d.ts.map +1 -0
  104. package/dist/lib/types/index.js +5 -0
  105. package/dist/lib/types/map-generator-config.d.ts +8 -0
  106. package/dist/lib/types/map-generator-config.d.ts.map +1 -0
  107. package/dist/lib/types/map-generator-config.js +1 -0
  108. package/dist/lib/types/object-def.d.ts +58 -0
  109. package/dist/lib/types/object-def.d.ts.map +1 -0
  110. package/dist/lib/types/object-def.js +5 -0
  111. package/dist/lib/types/placed-object.d.ts +19 -0
  112. package/dist/lib/types/placed-object.d.ts.map +1 -0
  113. package/dist/lib/types/placed-object.js +10 -0
  114. package/dist/lib/types/prng-interface.d.ts +14 -0
  115. package/dist/lib/types/prng-interface.d.ts.map +1 -0
  116. package/dist/lib/types/prng-interface.js +1 -0
  117. package/dist/lib/utils/extract-canopy-zones.d.ts +22 -0
  118. package/dist/lib/utils/extract-canopy-zones.d.ts.map +1 -0
  119. package/dist/lib/utils/extract-canopy-zones.js +34 -0
  120. package/dist/lib/utils/sort-placed-objects.d.ts +3 -0
  121. package/dist/lib/utils/sort-placed-objects.d.ts.map +1 -0
  122. package/dist/lib/utils/sort-placed-objects.js +3 -0
  123. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  124. package/package.json +42 -0
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Generates jagged polygon points around an AABB border.
3
+ * Counter-clockwise winding: bottom→right→top→left.
4
+ * Corner points are NOT offset. Intermediate points are offset by random variation.
5
+ *
6
+ * Port of survev/shared/utils/terrainGen.ts:15-56.
7
+ */
8
+ export function generateJaggedAabbPoints(aabb, divisionsX, divisionsY, variation, random) {
9
+ const llX = aabb.min.x;
10
+ const llY = aabb.min.y;
11
+ const lrX = aabb.max.x;
12
+ const lrY = aabb.min.y;
13
+ const ulX = aabb.min.x;
14
+ const ulY = aabb.max.y;
15
+ const urX = aabb.max.x;
16
+ const urY = aabb.max.y;
17
+ const distanceX = lrX - llX;
18
+ const distanceY = ulY - llY;
19
+ const spanX = distanceX / (divisionsX + 1);
20
+ const spanY = distanceY / (divisionsY + 1);
21
+ const points = [];
22
+ // Bottom edge: left → right
23
+ points.push({ x: llX, y: llY });
24
+ for (let i = 1; i <= divisionsX; i++) {
25
+ const vari = variation > 0 ? (random.getFloat() * 2 - 1) * variation : 0;
26
+ points.push({ x: llX + spanX * i, y: llY + vari });
27
+ }
28
+ // Right edge: bottom → top
29
+ points.push({ x: lrX, y: lrY });
30
+ for (let i = 1; i <= divisionsY; i++) {
31
+ const vari = variation > 0 ? (random.getFloat() * 2 - 1) * variation : 0;
32
+ points.push({ x: lrX + vari, y: lrY + spanY * i });
33
+ }
34
+ // Top edge: right → left
35
+ points.push({ x: urX, y: urY });
36
+ for (let i = 1; i <= divisionsX; i++) {
37
+ const vari = variation > 0 ? (random.getFloat() * 2 - 1) * variation : 0;
38
+ points.push({ x: urX - spanX * i, y: urY + vari });
39
+ }
40
+ // Left edge: top → bottom
41
+ points.push({ x: ulX, y: ulY });
42
+ for (let i = 1; i <= divisionsY; i++) {
43
+ const vari = variation > 0 ? (random.getFloat() * 2 - 1) * variation : 0;
44
+ points.push({ x: ulX + vari, y: ulY - spanY * i });
45
+ }
46
+ return points;
47
+ }
@@ -0,0 +1,19 @@
1
+ import type { ReadonlyVec2, AABB, Polygon } from '../types/geometry.js';
2
+ /**
3
+ * Point-in-polygon test using ray casting algorithm.
4
+ * Uses AABB pre-check for early exit.
5
+ */
6
+ export declare function pointInPolygon(point: ReadonlyVec2, polygon: Polygon): boolean;
7
+ /**
8
+ * Polygon area via shoelace formula. Returns absolute value (positive regardless of winding).
9
+ */
10
+ export declare function polygonArea(points: readonly ReadonlyVec2[]): number;
11
+ /**
12
+ * Squared distance from a point to a line segment.
13
+ */
14
+ export declare function distToSegmentSq(point: ReadonlyVec2, segA: ReadonlyVec2, segB: ReadonlyVec2): number;
15
+ /**
16
+ * Compute AABB bounds for a set of points.
17
+ */
18
+ export declare function computePolygonBounds(points: readonly ReadonlyVec2[]): AABB;
19
+ //# sourceMappingURL=polygon-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polygon-utils.d.ts","sourceRoot":"","sources":["../../../src/lib/math/polygon-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAExE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAkB7E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CASnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,YAAY,GACjB,MAAM,CAoBR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI,CAiB1E"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Point-in-polygon test using ray casting algorithm.
3
+ * Uses AABB pre-check for early exit.
4
+ */
5
+ export function pointInPolygon(point, polygon) {
6
+ const pts = polygon.points;
7
+ const n = polygon.count;
8
+ if (n < 3)
9
+ return false;
10
+ let inside = false;
11
+ for (let i = 0, j = n - 1; i < n; j = i++) {
12
+ const xi = pts[i].x;
13
+ const yi = pts[i].y;
14
+ const xj = pts[j].x;
15
+ const yj = pts[j].y;
16
+ if (((yi > point.y) !== (yj > point.y)) &&
17
+ (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi)) {
18
+ inside = !inside;
19
+ }
20
+ }
21
+ return inside;
22
+ }
23
+ /**
24
+ * Polygon area via shoelace formula. Returns absolute value (positive regardless of winding).
25
+ */
26
+ export function polygonArea(points) {
27
+ const n = points.length;
28
+ if (n < 3)
29
+ return 0;
30
+ let area = 0;
31
+ for (let i = 0, j = n - 1; i < n; j = i++) {
32
+ area += (points[j].x + points[i].x) * (points[j].y - points[i].y);
33
+ }
34
+ return Math.abs(area) / 2;
35
+ }
36
+ /**
37
+ * Squared distance from a point to a line segment.
38
+ */
39
+ export function distToSegmentSq(point, segA, segB) {
40
+ const dx = segB.x - segA.x;
41
+ const dy = segB.y - segA.y;
42
+ const lenSq = dx * dx + dy * dy;
43
+ if (lenSq === 0) {
44
+ // Degenerate segment (both points same)
45
+ const px = point.x - segA.x;
46
+ const py = point.y - segA.y;
47
+ return px * px + py * py;
48
+ }
49
+ let t = ((point.x - segA.x) * dx + (point.y - segA.y) * dy) / lenSq;
50
+ t = Math.max(0, Math.min(1, t));
51
+ const projX = segA.x + t * dx;
52
+ const projY = segA.y + t * dy;
53
+ const ex = point.x - projX;
54
+ const ey = point.y - projY;
55
+ return ex * ex + ey * ey;
56
+ }
57
+ /**
58
+ * Compute AABB bounds for a set of points.
59
+ */
60
+ export function computePolygonBounds(points) {
61
+ let minX = Infinity;
62
+ let minY = Infinity;
63
+ let maxX = -Infinity;
64
+ let maxY = -Infinity;
65
+ for (const p of points) {
66
+ if (p.x < minX)
67
+ minX = p.x;
68
+ if (p.y < minY)
69
+ minY = p.y;
70
+ if (p.x > maxX)
71
+ maxX = p.x;
72
+ if (p.y > maxY)
73
+ maxY = p.y;
74
+ }
75
+ return {
76
+ min: { x: minX, y: minY },
77
+ max: { x: maxX, y: maxY },
78
+ };
79
+ }
@@ -0,0 +1,12 @@
1
+ import type { ReadonlyVec2 } from '../types/geometry.js';
2
+ import type { GeneratedRiver } from '../types/generated-river.js';
3
+ export interface RiverPolygonOptions {
4
+ splinePoints: ReadonlyVec2[];
5
+ waterWidth: number;
6
+ shoreWidth: number;
7
+ looped: boolean;
8
+ mapWidth: number;
9
+ mapHeight: number;
10
+ }
11
+ export declare function generateRiverPolygon(opts: RiverPolygonOptions): GeneratedRiver;
12
+ //# sourceMappingURL=river-polygon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"river-polygon.d.ts","sourceRoot":"","sources":["../../../src/lib/math/river-polygon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,mBAAmB,GAAG,cAAc,CA6E9E"}
@@ -0,0 +1,84 @@
1
+ import { Spline } from './spline.js';
2
+ import { computePolygonBounds } from './polygon-utils.js';
3
+ export function generateRiverPolygon(opts) {
4
+ const { splinePoints, waterWidth, shoreWidth, looped, mapWidth, mapHeight } = opts;
5
+ const spline = new Spline(splinePoints, looped);
6
+ const numSamples = Math.max(splinePoints.length * 4, 20);
7
+ const waterLeft = [];
8
+ const waterRight = [];
9
+ const shoreLeft = [];
10
+ const shoreRight = [];
11
+ for (let i = 0; i <= numSamples; i++) {
12
+ const t = i / numSamples;
13
+ const pos = spline.getPos(t);
14
+ const normal = spline.getNormal(t);
15
+ let ww = waterWidth;
16
+ let sw = shoreWidth;
17
+ if (!looped) {
18
+ // Endpoint widening: (1 + end^3 * 1.5) * width
19
+ const end = 1 - Math.min(t, 1 - t) * 2; // 1 at endpoints, 0 at center
20
+ const endFactor = Math.max(0, end);
21
+ const widening = 1 + endFactor * endFactor * endFactor * 1.5;
22
+ ww *= widening;
23
+ sw *= widening;
24
+ // Map edge normal adjustment for flush ends
25
+ if (i === 0 || i === numSamples) {
26
+ const edgeNormal = getMapEdgeNormal(pos, mapWidth, mapHeight);
27
+ if (edgeNormal) {
28
+ // Use edge normal instead of spline normal for flush alignment
29
+ waterLeft.push({ x: pos.x + edgeNormal.x * ww, y: pos.y + edgeNormal.y * ww });
30
+ waterRight.push({ x: pos.x - edgeNormal.x * ww, y: pos.y - edgeNormal.y * ww });
31
+ shoreLeft.push({ x: pos.x + edgeNormal.x * (ww + sw), y: pos.y + edgeNormal.y * (ww + sw) });
32
+ shoreRight.push({ x: pos.x - edgeNormal.x * (ww + sw), y: pos.y - edgeNormal.y * (ww + sw) });
33
+ continue;
34
+ }
35
+ }
36
+ }
37
+ waterLeft.push({ x: pos.x + normal.x * ww, y: pos.y + normal.y * ww });
38
+ waterRight.push({ x: pos.x - normal.x * ww, y: pos.y - normal.y * ww });
39
+ shoreLeft.push({ x: pos.x + normal.x * (ww + sw), y: pos.y + normal.y * (ww + sw) });
40
+ shoreRight.push({ x: pos.x - normal.x * (ww + sw), y: pos.y - normal.y * (ww + sw) });
41
+ }
42
+ // For looped shapes (lakes), the spline winds CW in screen coords.
43
+ // The normal points inward, so waterRight/shoreRight are the outward boundaries.
44
+ const waterPoints = looped
45
+ ? [...waterRight, ...waterRight.slice(0, 1)]
46
+ : [...waterLeft, ...waterRight.reverse()];
47
+ const shorePoints = looped
48
+ ? [...shoreRight, ...shoreRight.slice(0, 1)]
49
+ : [...shoreLeft, ...shoreRight.reverse()];
50
+ const waterPoly = { points: waterPoints, count: waterPoints.length };
51
+ const shorePoly = { points: shorePoints, count: shorePoints.length };
52
+ // Compute center
53
+ let cx = 0, cy = 0;
54
+ for (const p of splinePoints) {
55
+ cx += p.x;
56
+ cy += p.y;
57
+ }
58
+ cx /= splinePoints.length;
59
+ cy /= splinePoints.length;
60
+ const allPoints = [...waterPoints, ...shorePoints];
61
+ const aabb = computePolygonBounds(allPoints);
62
+ return {
63
+ splinePoints,
64
+ waterWidth,
65
+ shoreWidth,
66
+ looped,
67
+ center: { x: cx, y: cy },
68
+ waterPoly,
69
+ shorePoly,
70
+ aabb,
71
+ };
72
+ }
73
+ function getMapEdgeNormal(pos, mapWidth, mapHeight) {
74
+ const edgeThreshold = 5;
75
+ if (pos.x <= edgeThreshold)
76
+ return { x: 0, y: 1 };
77
+ if (pos.x >= mapWidth - edgeThreshold)
78
+ return { x: 0, y: 1 };
79
+ if (pos.y <= edgeThreshold)
80
+ return { x: 1, y: 0 };
81
+ if (pos.y >= mapHeight - edgeThreshold)
82
+ return { x: 1, y: 0 };
83
+ return null;
84
+ }
@@ -0,0 +1,15 @@
1
+ import type { ReadonlyVec2 } from '../types/geometry.js';
2
+ export declare class Spline {
3
+ readonly points: ReadonlyVec2[];
4
+ readonly arcLens: number[];
5
+ readonly totalArcLen: number;
6
+ readonly looped: boolean;
7
+ constructor(points: readonly ReadonlyVec2[], looped: boolean);
8
+ getPos(t: number): ReadonlyVec2;
9
+ getTangent(t: number): ReadonlyVec2;
10
+ getNormal(t: number): ReadonlyVec2;
11
+ getClosestTtoPoint(pos: ReadonlyVec2): number;
12
+ getTfromArcLen(arcLen: number): number;
13
+ getArcLen(t: number): number;
14
+ }
15
+ //# sourceMappingURL=spline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spline.d.ts","sourceRoot":"","sources":["../../../src/lib/math/spline.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,qBAAa,MAAM;IACjB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAEb,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,MAAM,EAAE,OAAO;IAsB5D,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,YAAY;IAQ/B,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,YAAY;IAQnC,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,YAAY;IASlC,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;IA0D7C,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAiBtC,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;CAS7B"}
@@ -0,0 +1,127 @@
1
+ import { MathOps } from '@lagless/math';
2
+ import { catmullRom, catmullRomDerivative, getControlPoints } from './catmull-rom.js';
3
+ import { distToSegmentSq } from './polygon-utils.js';
4
+ export class Spline {
5
+ points;
6
+ arcLens;
7
+ totalArcLen;
8
+ looped;
9
+ constructor(points, looped) {
10
+ this.looped = looped;
11
+ this.points = points.map(p => ({ x: p.x, y: p.y }));
12
+ const arcLenSamples = points.length * 4;
13
+ this.arcLens = [];
14
+ let curX = this.points[0].x;
15
+ let curY = this.points[0].y;
16
+ for (let i = 0; i <= arcLenSamples; i++) {
17
+ const t = i / arcLenSamples;
18
+ const next = this.getPos(t);
19
+ const dx = next.x - curX;
20
+ const dy = next.y - curY;
21
+ const prevLen = i === 0 ? 0 : this.arcLens[i - 1];
22
+ this.arcLens[i] = prevLen + MathOps.sqrt(dx * dx + dy * dy);
23
+ curX = next.x;
24
+ curY = next.y;
25
+ }
26
+ this.totalArcLen = this.arcLens[this.arcLens.length - 1];
27
+ }
28
+ getPos(t) {
29
+ const { pt, p0, p1, p2, p3 } = getControlPoints(t, this.points, this.looped);
30
+ return {
31
+ x: catmullRom(pt, p0.x, p1.x, p2.x, p3.x),
32
+ y: catmullRom(pt, p0.y, p1.y, p2.y, p3.y),
33
+ };
34
+ }
35
+ getTangent(t) {
36
+ const { pt, p0, p1, p2, p3 } = getControlPoints(t, this.points, this.looped);
37
+ return {
38
+ x: catmullRomDerivative(pt, p0.x, p1.x, p2.x, p3.x),
39
+ y: catmullRomDerivative(pt, p0.y, p1.y, p2.y, p3.y),
40
+ };
41
+ }
42
+ getNormal(t) {
43
+ const tangent = this.getTangent(t);
44
+ const len = MathOps.sqrt(tangent.x * tangent.x + tangent.y * tangent.y);
45
+ if (len === 0)
46
+ return { x: 0, y: 1 };
47
+ const nx = tangent.x / len;
48
+ const ny = tangent.y / len;
49
+ return { x: -ny, y: nx };
50
+ }
51
+ getClosestTtoPoint(pos) {
52
+ let closestDistSq = Number.MAX_VALUE;
53
+ let closestSegIdx = 0;
54
+ for (let i = 0; i < this.points.length - 1; i++) {
55
+ const dSq = distToSegmentSq(pos, this.points[i], this.points[i + 1]);
56
+ if (dSq < closestDistSq) {
57
+ closestDistSq = dSq;
58
+ closestSegIdx = i;
59
+ }
60
+ }
61
+ const s0 = this.points[closestSegIdx];
62
+ const s1 = this.points[closestSegIdx + 1];
63
+ const segX = s1.x - s0.x;
64
+ const segY = s1.y - s0.y;
65
+ const segDot = segX * segX + segY * segY;
66
+ const proj = segDot > 0
67
+ ? Math.max(0, Math.min(1, ((pos.x - s0.x) * segX + (pos.y - s0.y) * segY) / segDot))
68
+ : 0;
69
+ const len = this.points.length - 1;
70
+ const tMin = Math.max(0, Math.min(1, (closestSegIdx + proj - 0.1) / len));
71
+ const tMax = Math.max(0, Math.min(1, (closestSegIdx + proj + 0.1) / len));
72
+ let nearestT = (closestSegIdx + proj) / len;
73
+ let nearestDistSq = Number.MAX_VALUE;
74
+ for (let i = 0; i <= 8; i++) {
75
+ const testT = tMin + (i / 8) * (tMax - tMin);
76
+ const testPos = this.getPos(testT);
77
+ const dx = testPos.x - pos.x;
78
+ const dy = testPos.y - pos.y;
79
+ const dSq = dx * dx + dy * dy;
80
+ if (dSq < nearestDistSq) {
81
+ nearestT = testT;
82
+ nearestDistSq = dSq;
83
+ }
84
+ }
85
+ const tangent = this.getTangent(nearestT);
86
+ const tanLen = MathOps.sqrt(tangent.x * tangent.x + tangent.y * tangent.y);
87
+ if (tanLen > 0) {
88
+ const nearest = this.getPos(nearestT);
89
+ const offset = (tangent.x * (pos.x - nearest.x) + tangent.y * (pos.y - nearest.y)) / tanLen;
90
+ const offsetT = nearestT + offset / (tanLen * len);
91
+ const offPos = this.getPos(offsetT);
92
+ const offDx = pos.x - offPos.x;
93
+ const offDy = pos.y - offPos.y;
94
+ const nDx = pos.x - nearest.x;
95
+ const nDy = pos.y - nearest.y;
96
+ if (offDx * offDx + offDy * offDy < nDx * nDx + nDy * nDy) {
97
+ nearestT = offsetT;
98
+ }
99
+ }
100
+ return nearestT;
101
+ }
102
+ getTfromArcLen(arcLen) {
103
+ arcLen = Math.max(0, Math.min(this.totalArcLen, arcLen));
104
+ let idx = 0;
105
+ while (idx < this.arcLens.length && arcLen > this.arcLens[idx]) {
106
+ idx++;
107
+ }
108
+ if (idx === 0)
109
+ return 0;
110
+ const prev = this.arcLens[idx - 1];
111
+ const curr = this.arcLens[idx];
112
+ const arcT = curr !== prev ? (arcLen - prev) / (curr - prev) : 0;
113
+ const arcCount = this.arcLens.length - 1;
114
+ const t0 = (idx - 1) / arcCount;
115
+ const t1 = idx / arcCount;
116
+ return t0 + arcT * (t1 - t0);
117
+ }
118
+ getArcLen(t) {
119
+ t = Math.max(0, Math.min(1, t));
120
+ const arcCount = this.arcLens.length - 1;
121
+ const idx0 = Math.floor(t * arcCount);
122
+ const idx1 = idx0 < arcCount ? idx0 + 1 : idx0;
123
+ const segLen = 1.0 / arcCount;
124
+ const arcT = segLen > 0 ? ((t % segLen) / segLen) : 0;
125
+ return this.arcLens[idx0] + arcT * (this.arcLens[idx1] - this.arcLens[idx0]);
126
+ }
127
+ }
@@ -0,0 +1,2 @@
1
+ export declare const CANOPY_SENSOR_TAG = 1;
2
+ //# sourceMappingURL=canopy-sensor-tag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canopy-sensor-tag.d.ts","sourceRoot":"","sources":["../../../src/lib/physics/canopy-sensor-tag.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,IAAI,CAAC"}
@@ -0,0 +1 @@
1
+ export const CANOPY_SENSOR_TAG = 1;
@@ -0,0 +1,12 @@
1
+ import type { PlacedObject } from '../types/placed-object.js';
2
+ import type { MapObjectRegistry } from '../types/object-def.js';
3
+ export interface MapPhysicsProvider {
4
+ createFixedBody(x: number, y: number, rotation: number): unknown;
5
+ createCircleCollider(body: unknown, radius: number, offsetX: number, offsetY: number, isSensor: boolean, tag?: number, collisionGroup?: number): void;
6
+ createCuboidCollider(body: unknown, halfW: number, halfH: number, offsetX: number, offsetY: number, isSensor: boolean, tag?: number, collisionGroup?: number): void;
7
+ }
8
+ export interface CreateMapCollidersOptions {
9
+ skipTags?: readonly number[];
10
+ }
11
+ export declare function createMapColliders(physics: MapPhysicsProvider, objects: readonly PlacedObject[], registry: MapObjectRegistry, options?: CreateMapCollidersOptions): void;
12
+ //# sourceMappingURL=create-map-colliders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-map-colliders.d.ts","sourceRoot":"","sources":["../../../src/lib/physics/create-map-colliders.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACjE,oBAAoB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtJ,oBAAoB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrK;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,CAAC,EAAE,yBAAyB,GAClC,IAAI,CAIN"}
@@ -0,0 +1,29 @@
1
+ import { ShapeType } from '../types/geometry.js';
2
+ export function createMapColliders(physics, objects, registry, options) {
3
+ for (const obj of objects) {
4
+ placeObject(physics, obj, registry, options);
5
+ }
6
+ }
7
+ function placeObject(physics, obj, registry, options) {
8
+ const def = registry.get(obj.typeId);
9
+ if (!def)
10
+ return;
11
+ const body = physics.createFixedBody(obj.posX, obj.posY, obj.rotation);
12
+ const skipTags = options?.skipTags;
13
+ for (const collider of def.colliders) {
14
+ if (skipTags && collider.tag !== undefined && skipTags.includes(collider.tag))
15
+ continue;
16
+ const ox = (collider.offsetX ?? 0) * obj.scale;
17
+ const oy = (collider.offsetY ?? 0) * obj.scale;
18
+ const isSensor = collider.isSensor ?? false;
19
+ if (collider.shape.type === ShapeType.Circle) {
20
+ physics.createCircleCollider(body, collider.shape.radius * obj.scale, ox, oy, isSensor, collider.tag, collider.collisionGroup);
21
+ }
22
+ else {
23
+ physics.createCuboidCollider(body, collider.shape.halfWidth * obj.scale, collider.shape.halfHeight * obj.scale, ox, oy, isSensor, collider.tag, collider.collisionGroup);
24
+ }
25
+ }
26
+ for (const child of obj.children) {
27
+ placeObject(physics, child, registry, options);
28
+ }
29
+ }
@@ -0,0 +1,3 @@
1
+ import type { BiomeConfig } from '../types/feature-configs.js';
2
+ export declare const STANDARD_BIOME: BiomeConfig;
3
+ //# sourceMappingURL=standard-biome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-biome.d.ts","sourceRoot":"","sources":["../../../src/lib/presets/standard-biome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE/D,eAAO,MAAM,cAAc,EAAE,WAQ5B,CAAC"}
@@ -0,0 +1,9 @@
1
+ export const STANDARD_BIOME = {
2
+ background: 0x80af49,
3
+ water: 0x3d85c6,
4
+ waterRipple: 0x3478b2,
5
+ beach: 0xcdb35b,
6
+ riverbank: 0x905e24,
7
+ grass: 0x80af49,
8
+ underground: 0x1b0d00,
9
+ };
@@ -0,0 +1,6 @@
1
+ import { MapGenerator } from '../core/map-generator.js';
2
+ export interface StandardGeneratorOptions {
3
+ scale?: 'small' | 'large';
4
+ }
5
+ export declare function createStandardGenerator(options?: StandardGeneratorOptions): MapGenerator;
6
+ //# sourceMappingURL=standard-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-map.d.ts","sourceRoot":"","sources":["../../../src/lib/presets/standard-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAYxD,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC3B;AAED,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,wBAAwB,GAAG,YAAY,CAoDxF"}
@@ -0,0 +1,61 @@
1
+ import { MapGenerator } from '../core/map-generator.js';
2
+ import { BiomeFeature } from '../features/biome-feature.js';
3
+ import { ShoreFeature } from '../features/shore-feature.js';
4
+ import { GrassFeature } from '../features/grass-feature.js';
5
+ import { RiverFeature } from '../features/river-feature.js';
6
+ import { LakeFeature } from '../features/lake-feature.js';
7
+ import { ObjectPlacementFeature } from '../features/object-placement-feature.js';
8
+ import { PlacementKind } from '../types/feature-configs.js';
9
+ import { TerrainZone } from '../types/placed-object.js';
10
+ import { STANDARD_BIOME } from './standard-biome.js';
11
+ import { StandardObjectType, STANDARD_OBJECT_REGISTRY } from './standard-objects.js';
12
+ export function createStandardGenerator(options) {
13
+ const scaleFactor = options?.scale === 'large' ? 1.5 : 1.0;
14
+ const generator = new MapGenerator({
15
+ baseWidth: 720,
16
+ baseHeight: 720,
17
+ scale: scaleFactor,
18
+ extension: 80,
19
+ gridSize: 16,
20
+ });
21
+ generator
22
+ .addFeature(new BiomeFeature(), STANDARD_BIOME)
23
+ .addFeature(new ShoreFeature(), {
24
+ inset: 48,
25
+ divisions: 12,
26
+ variation: 4,
27
+ })
28
+ .addFeature(new GrassFeature(), {
29
+ inset: 18,
30
+ variation: 3,
31
+ })
32
+ .addFeature(new RiverFeature(), {
33
+ weights: [
34
+ { weight: 0.10, widths: [4] },
35
+ { weight: 0.25, widths: [8, 4] },
36
+ { weight: 0.20, widths: [16, 8, 4] },
37
+ { weight: 0.15, widths: [8, 6, 4] },
38
+ { weight: 0.15, widths: [8, 4] },
39
+ { weight: 0.15, widths: [4] },
40
+ ],
41
+ subdivisionPasses: 5,
42
+ masks: [],
43
+ })
44
+ .addFeature(new LakeFeature(), {
45
+ lakes: [
46
+ {
47
+ odds: 0.5,
48
+ innerRad: 30,
49
+ outerRad: 50,
50
+ spawnBound: { pos: { x: 0.5, y: 0.5 }, rad: 100 },
51
+ },
52
+ ],
53
+ })
54
+ .addFeature(new ObjectPlacementFeature(), {
55
+ registry: STANDARD_OBJECT_REGISTRY,
56
+ stages: [
57
+ { kind: PlacementKind.Density, typeId: StandardObjectType.Tree, density: 100, terrainZone: TerrainZone.Grass },
58
+ ],
59
+ });
60
+ return generator;
61
+ }
@@ -0,0 +1,6 @@
1
+ import type { MapObjectRegistry } from '../types/object-def.js';
2
+ export declare enum StandardObjectType {
3
+ Tree = 0
4
+ }
5
+ export declare const STANDARD_OBJECT_REGISTRY: MapObjectRegistry;
6
+ //# sourceMappingURL=standard-objects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-objects.d.ts","sourceRoot":"","sources":["../../../src/lib/presets/standard-objects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAI9E,oBAAY,kBAAkB;IAAG,IAAI,IAAI;CAAE;AAmB3C,eAAO,MAAM,wBAAwB,EAAE,iBAErC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { RenderLayer } from '../types/object-def.js';
2
+ import { ShapeType } from '../types/geometry.js';
3
+ export var StandardObjectType;
4
+ (function (StandardObjectType) {
5
+ StandardObjectType[StandardObjectType["Tree"] = 0] = "Tree";
6
+ })(StandardObjectType || (StandardObjectType = {}));
7
+ const TREE_DEF = {
8
+ typeId: StandardObjectType.Tree,
9
+ colliders: [
10
+ { shape: { type: ShapeType.Circle, radius: 3 } },
11
+ ],
12
+ visuals: [
13
+ { texture: 'tree-trunk', layer: RenderLayer.Ground },
14
+ { texture: 'tree-foliage', layer: RenderLayer.Canopy },
15
+ ],
16
+ scaleRange: [0.8, 1.2],
17
+ mapDisplay: {
18
+ shapes: [
19
+ { collider: { type: ShapeType.Circle, radius: 3 }, color: 0x2d5a1e, scale: 1 },
20
+ ],
21
+ },
22
+ };
23
+ export const STANDARD_OBJECT_REGISTRY = new Map([
24
+ [StandardObjectType.Tree, TREE_DEF],
25
+ ]);
@@ -0,0 +1,8 @@
1
+ import type { MapCollisionShape } from './geometry.js';
2
+ export interface ICollisionProvider {
3
+ addShape(id: number, shape: MapCollisionShape, posX: number, posY: number, rotation: number, scale: number): void;
4
+ testShape(shape: MapCollisionShape, posX: number, posY: number, rotation: number, scale: number): boolean;
5
+ removeShape(id: number): void;
6
+ clear(): void;
7
+ }
8
+ //# sourceMappingURL=collision-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collision-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/types/collision-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAClH,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1G,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,IAAI,IAAI,CAAC;CACf"}
@@ -0,0 +1 @@
1
+ export {};