@dryanovski/gamefoo 0.0.1 → 0.2.0

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 (75) hide show
  1. package/dist/core/animate.d.ts +129 -0
  2. package/dist/core/animate.d.ts.map +1 -0
  3. package/dist/core/asset.d.ts +59 -0
  4. package/dist/core/asset.d.ts.map +1 -0
  5. package/dist/core/behaviour.d.ts +118 -0
  6. package/dist/core/behaviour.d.ts.map +1 -1
  7. package/dist/core/behaviours/collidable.d.ts +203 -4
  8. package/dist/core/behaviours/collidable.d.ts.map +1 -1
  9. package/dist/core/behaviours/control.d.ts +51 -3
  10. package/dist/core/behaviours/control.d.ts.map +1 -1
  11. package/dist/core/behaviours/healtkit.d.ts +120 -3
  12. package/dist/core/behaviours/healtkit.d.ts.map +1 -1
  13. package/dist/core/behaviours/sprite_render.d.ts +141 -0
  14. package/dist/core/behaviours/sprite_render.d.ts.map +1 -0
  15. package/dist/core/camera.d.ts +101 -0
  16. package/dist/core/camera.d.ts.map +1 -1
  17. package/dist/core/engine.d.ts +377 -15
  18. package/dist/core/engine.d.ts.map +1 -1
  19. package/dist/core/fonts/font_bitmap.d.ts +156 -0
  20. package/dist/core/fonts/font_bitmap.d.ts.map +1 -0
  21. package/dist/core/fonts/font_bitmap_prebuild.d.ts +102 -0
  22. package/dist/core/fonts/font_bitmap_prebuild.d.ts.map +1 -0
  23. package/dist/core/fonts/internal/font_3x5.d.ts +76 -0
  24. package/dist/core/fonts/internal/font_3x5.d.ts.map +1 -0
  25. package/dist/core/fonts/internal/font_4x6.d.ts +76 -0
  26. package/dist/core/fonts/internal/font_4x6.d.ts.map +1 -0
  27. package/dist/core/fonts/internal/font_5x5.d.ts +79 -0
  28. package/dist/core/fonts/internal/font_5x5.d.ts.map +1 -0
  29. package/dist/core/fonts/internal/font_6x8.d.ts +76 -0
  30. package/dist/core/fonts/internal/font_6x8.d.ts.map +1 -0
  31. package/dist/core/fonts/internal/font_8x13.d.ts +76 -0
  32. package/dist/core/fonts/internal/font_8x13.d.ts.map +1 -0
  33. package/dist/core/fonts/internal/font_8x8.d.ts +76 -0
  34. package/dist/core/fonts/internal/font_8x8.d.ts.map +1 -0
  35. package/dist/core/game_object_register.d.ts +101 -1
  36. package/dist/core/game_object_register.d.ts.map +1 -1
  37. package/dist/core/input.d.ts +131 -0
  38. package/dist/core/input.d.ts.map +1 -1
  39. package/dist/core/sprite.d.ts +232 -0
  40. package/dist/core/sprite.d.ts.map +1 -0
  41. package/dist/core/utils/perlin_noise.d.ts +136 -0
  42. package/dist/core/utils/perlin_noise.d.ts.map +1 -0
  43. package/dist/core/world.d.ts +147 -0
  44. package/dist/core/world.d.ts.map +1 -1
  45. package/dist/debug/monitor.d.ts +12 -0
  46. package/dist/debug/monitor.d.ts.map +1 -0
  47. package/dist/decorators/index.d.ts +2 -0
  48. package/dist/decorators/index.d.ts.map +1 -0
  49. package/dist/decorators/log.d.ts +33 -0
  50. package/dist/decorators/log.d.ts.map +1 -0
  51. package/dist/entities/dynamic_entity.d.ts +82 -0
  52. package/dist/entities/dynamic_entity.d.ts.map +1 -1
  53. package/dist/entities/entity.d.ts +216 -11
  54. package/dist/entities/entity.d.ts.map +1 -1
  55. package/dist/entities/player.d.ts +76 -0
  56. package/dist/entities/player.d.ts.map +1 -1
  57. package/dist/entities/text.d.ts +52 -0
  58. package/dist/entities/text.d.ts.map +1 -0
  59. package/dist/index.d.ts +29 -1
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +23 -604
  62. package/dist/index.js.map +3 -15
  63. package/dist/subsystems/camera_system.d.ts +25 -0
  64. package/dist/subsystems/camera_system.d.ts.map +1 -0
  65. package/dist/subsystems/collision_system.d.ts +16 -0
  66. package/dist/subsystems/collision_system.d.ts.map +1 -0
  67. package/dist/subsystems/monitor_system.d.ts +17 -0
  68. package/dist/subsystems/monitor_system.d.ts.map +1 -0
  69. package/dist/subsystems/object_system.d.ts +18 -0
  70. package/dist/subsystems/object_system.d.ts.map +1 -0
  71. package/dist/subsystems/types.d.ts +40 -0
  72. package/dist/subsystems/types.d.ts.map +1 -0
  73. package/dist/types.d.ts +140 -0
  74. package/dist/types.d.ts.map +1 -1
  75. package/package.json +25 -11
@@ -1,15 +1,146 @@
1
+ /**
2
+ * Unified keyboard and mouse input manager.
3
+ *
4
+ * `Input` listens to `keydown`, `keyup`, `mousedown`, `mouseup`, and
5
+ * `mousemove` events on the `window` and exposes a polling API so game
6
+ * logic can query the current state at any point during a frame rather
7
+ * than relying on event callbacks.
8
+ *
9
+ * All keyboard keys are stored **lowercased** for case-insensitive
10
+ * look-ups.
11
+ *
12
+ * @category Core
13
+ * @since 0.1.0
14
+ *
15
+ * @example Polling keys
16
+ * ```ts
17
+ * const input = new Input();
18
+ *
19
+ * function update() {
20
+ * if (input.isKeyDown("w")) {
21
+ * player.y -= speed;
22
+ * }
23
+ * }
24
+ * ```
25
+ *
26
+ * @example Checking mouse state
27
+ * ```ts
28
+ * const input = new Input();
29
+ *
30
+ * if (input.isMouseButtonDown(0)) { // left-click
31
+ * const { x, y } = input.getMousePosition();
32
+ * shoot(x, y);
33
+ * }
34
+ * ```
35
+ *
36
+ * @see {@link Control} — behaviour that consumes `Input` for player movement
37
+ */
1
38
  export default class Input {
39
+ /**
40
+ * Set of currently-pressed keyboard keys (lowercased).
41
+ *
42
+ * Populated on `keydown`, cleared on `keyup`.
43
+ */
2
44
  private keys;
45
+ /**
46
+ * Set of currently-pressed mouse button indices.
47
+ *
48
+ * Standard mapping: `0` = left, `1` = middle, `2` = right.
49
+ */
3
50
  private mouseButtons;
51
+ /**
52
+ * Last known mouse position in **client** (viewport) coordinates.
53
+ *
54
+ * @defaultValue `{ x: 0, y: 0 }`
55
+ */
4
56
  private mousePosition;
57
+ /**
58
+ * Creates a new `Input` instance and attaches global event listeners
59
+ * to the `window`.
60
+ *
61
+ * @remarks
62
+ * Only one `Input` instance should exist at a time to avoid
63
+ * duplicate listeners. If you need to tear down, call {@link Input.reset}
64
+ * to clear tracked state.
65
+ */
5
66
  constructor();
67
+ /**
68
+ * Checks whether a specific key is currently held down.
69
+ *
70
+ * @param key - The key name to check (case-insensitive).
71
+ * Uses the standard {@link KeyboardEvent.key} values (e.g. `"a"`,
72
+ * `"ArrowLeft"`, `"Shift"`).
73
+ * @returns `true` if the key is currently pressed.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * if (input.isKeyDown("space")) {
78
+ * player.jump();
79
+ * }
80
+ * ```
81
+ */
6
82
  isKeyDown(key: string): boolean;
83
+ /**
84
+ * Returns a snapshot of all keys that are currently held down.
85
+ *
86
+ * The returned `Set` is a **copy** — mutating it does not affect
87
+ * the internal state.
88
+ *
89
+ * @returns A new `Set<string>` of pressed key names (lowercased).
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const pressed = input.getPressedKeys();
94
+ * console.log([...pressed]); // e.g. ["w", "shift"]
95
+ * ```
96
+ */
7
97
  getPressedKeys(): Set<string>;
98
+ /**
99
+ * Checks whether a specific mouse button is currently held down.
100
+ *
101
+ * @param button - The mouse button index (`0` = left, `1` = middle,
102
+ * `2` = right).
103
+ * @returns `true` if the button is currently pressed.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * if (input.isMouseButtonDown(2)) {
108
+ * openContextMenu();
109
+ * }
110
+ * ```
111
+ */
8
112
  isMouseButtonDown(button: number): boolean;
113
+ /**
114
+ * Returns the last known mouse position in client (viewport)
115
+ * coordinates.
116
+ *
117
+ * The returned object is a **copy** — mutating it does not affect
118
+ * the internal state.
119
+ *
120
+ * @returns An `{ x, y }` object with the mouse coordinates.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * const pos = input.getMousePosition();
125
+ * ctx.fillRect(pos.x, pos.y, 4, 4); // draw cursor dot
126
+ * ```
127
+ */
9
128
  getMousePosition(): {
10
129
  x: number;
11
130
  y: number;
12
131
  };
132
+ /**
133
+ * Clears all tracked key and mouse-button state.
134
+ *
135
+ * Useful when pausing the game or switching scenes to prevent stale
136
+ * input from carrying over.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * engine.pause();
141
+ * input.reset();
142
+ * ```
143
+ */
13
144
  reset(): void;
14
145
  }
15
146
  //# sourceMappingURL=input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../core/input.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,aAAa,CAA4C;;IAyBjE,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI/B,cAAc,IAAI,GAAG,CAAC,MAAM,CAAC;IAI7B,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI1C,gBAAgB,IAAI;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAI5C,KAAK,IAAI,IAAI;CAId"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/core/input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB;;;;OAIG;IACH,OAAO,CAAC,IAAI,CAA0B;IAEtC;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAA0B;IAE9C;;;;OAIG;IACH,OAAO,CAAC,aAAa,CAA4C;IAEjE;;;;;;;;OAQG;;IAwBH;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI/B;;;;;;;;;;;;;OAaG;IACH,cAAc,IAAI,GAAG,CAAC,MAAM,CAAC;IAI7B;;;;;;;;;;;;;OAaG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI1C;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,IAAI;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAI5C;;;;;;;;;;;OAWG;IACH,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Describes a single named animation within a {@link Sprite} sheet.
3
+ *
4
+ * @category Core
5
+ * @since 0.1.0
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const walkAnim: AnimationDefinition = {
10
+ * frames: [0, 1, 2, 3],
11
+ * duration: 0.15,
12
+ * loop: true,
13
+ * };
14
+ * ```
15
+ */
16
+ interface AnimationDefinition {
17
+ /** Ordered frame indices into the spritesheet grid. */
18
+ frames: (string | number)[];
19
+ /** Time in seconds each frame is displayed before advancing. */
20
+ duration: number;
21
+ /** Whether the animation restarts from frame 0 after the last frame. */
22
+ loop: boolean;
23
+ }
24
+ /**
25
+ * Describes the position and size of a single frame within a {@link Sprite}
26
+ * sheet.
27
+ *
28
+ * @category Core
29
+ * @since 0.2.0
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const frame: SpriteFrame = {
34
+ * x: 32,
35
+ * y: 64,
36
+ * width: 32,
37
+ * height: 32,
38
+ * anchor: { x: 16, y: 16 },
39
+ * };
40
+ * ```
41
+ */
42
+ interface SpriteFrame {
43
+ x: number;
44
+ y: number;
45
+ width: number;
46
+ height: number;
47
+ anchor?: {
48
+ x: number;
49
+ y: number;
50
+ };
51
+ }
52
+ /**
53
+ * Configuration options for slicing a {@link Sprite} sheet into a grid of
54
+ * frames.
55
+ *
56
+ * @category Core
57
+ * @since 0.2.0
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const config: GridConfig = {
62
+ * frameWidth: 32,
63
+ * frameHeight: 32,
64
+ * offsetX: 0,
65
+ * offsetY: 0,
66
+ * spacingX: 0,
67
+ * spacingY: 0,
68
+ * count: 16,
69
+ * };
70
+ * ```
71
+ */
72
+ interface GridConfig {
73
+ frameWidth: number;
74
+ frameHeight: number;
75
+ offsetX?: number;
76
+ offsetY?: number;
77
+ spacingX?: number;
78
+ spacingY?: number;
79
+ count?: number;
80
+ }
81
+ /**
82
+ * Metadata wrapper around an {@link HTMLImageElement} that describes how
83
+ * it is sliced into a uniform grid of frames and what named animations
84
+ * are available.
85
+ *
86
+ * `Sprite` does **not** handle rendering itself — use
87
+ * {@link SpriteRender} to play animations on an entity.
88
+ *
89
+ * @category Core
90
+ * @since 0.1.0
91
+ *
92
+ * @example Loading and creating a sprite
93
+ * ```ts
94
+ * import { Asset } from "gamefoo";
95
+ *
96
+ * const image = await Asset.load("hero.png");
97
+ * const sprite = new Sprite(image, 32, 32, {
98
+ * idle: { frames: [0, 1], duration: 0.25, loop: true },
99
+ * run: { frames: [2, 3, 4, 5], duration: 0.1, loop: true },
100
+ * });
101
+ * ```
102
+ *
103
+ * @example Querying frame coordinates
104
+ * ```ts
105
+ * const rect = sprite.getFrameRect(5);
106
+ * ctx.drawImage(
107
+ * sprite.image,
108
+ * rect.x, rect.y, rect.width, rect.height,
109
+ * destX, destY, rect.width, rect.height,
110
+ * );
111
+ * ```
112
+ *
113
+ * @see {@link SpriteRender} — behaviour that plays sprite animations
114
+ * @see {@link Asset} — image loading utility
115
+ */
116
+ export default class Sprite {
117
+ /** The underlying image element containing the full spritesheet. */
118
+ image: HTMLImageElement;
119
+ /** Width of a single frame cell in pixels. */
120
+ readonly width: number;
121
+ /** Height of a single frame cell in pixels. */
122
+ readonly height: number;
123
+ /**
124
+ * Number of frame columns in the spritesheet, computed as
125
+ * `Math.floor(image.width / width)`.
126
+ */
127
+ readonly columns: number;
128
+ /**
129
+ * Number of frame rows in the spritesheet, computed as
130
+ * `Math.floor(image.height / height)`.
131
+ */
132
+ readonly rows: number;
133
+ /**
134
+ * Named animation definitions keyed by animation name.
135
+ *
136
+ * Populated from the optional `animations` parameter passed to the
137
+ * constructor.
138
+ */
139
+ animations: Map<string, AnimationDefinition>;
140
+ /**
141
+ * @since 0.2.0
142
+ */
143
+ frames: Map<number | string, SpriteFrame>;
144
+ /**
145
+ * Creates a new spritesheet descriptor.
146
+ *
147
+ * @param image - A fully-loaded `HTMLImageElement` containing the
148
+ * spritesheet texture.
149
+ * @param width - Width of each individual frame in pixels.
150
+ * @param height - Height of each individual frame in pixels.
151
+ * @param animations - Optional map of named animation definitions.
152
+ * Keys are animation names (e.g. `"idle"`, `"run"`).
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * const sprite = new Sprite(img, 64, 64, {
157
+ * idle: { frames: [0], duration: 1, loop: false },
158
+ * });
159
+ * ```
160
+ */
161
+ constructor(image: HTMLImageElement, width: number, height: number, animations?: Record<string, AnimationDefinition>);
162
+ /**
163
+ * Alternative constructor for spritesheets that are already sliced into a
164
+ * uniform grid of frames.
165
+ *
166
+ * @since 0.2.0
167
+ *
168
+ * @param image - A fully-loaded `HTMLImageElement` containing the
169
+ * spritesheet texture.
170
+ * @param config - Configuration options for slicing the image into a
171
+ * grid of frames.
172
+ * @param animations - Optional map of named animation definitions.
173
+ * Keys are animation names (e.g. `"idle"`, `"run"`).
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * const sprite = Sprite.fromGrid(img, {
178
+ * frameWidth: 64,
179
+ *
180
+ * frameHeight: 64,
181
+ * offsetX: 0,
182
+ * offsetY: 0,
183
+ * spacingX: 0,
184
+ * spacingY: 0,
185
+ * count: 16,
186
+ * }, {
187
+ * idle: { frames: [0, 1], duration: 0.25, loop: true },
188
+ * run: { frames: [2, 3, 4, 5], duration: 0.1, loop: true },
189
+ * });
190
+ * ```
191
+ */
192
+ static fromGrid(image: HTMLImageElement, config: GridConfig, animations?: Record<string, AnimationDefinition>): Sprite;
193
+ /**
194
+ * Helper method to compute frame rectangles for a spritesheet sliced into a
195
+ * uniform grid.
196
+ *
197
+ * @since 0.2.0
198
+ *
199
+ * @param image - A fully-loaded `HTMLImageElement` containing the
200
+ * spritesheet texture.
201
+ * @param config - Configuration options for slicing the image into a grid of
202
+ * frames.
203
+ *
204
+ * @returns A map of frame indices to their corresponding source rectangles.
205
+ * Frame indices are zero-based and laid out left-to-right, top-to-bottom.
206
+ * The source rectangles are in pixel coordinates relative to the top-left corner
207
+ * of the source image.
208
+ */
209
+ private static generateGridFrames;
210
+ static fromAtlas(image: HTMLImageElement, regions: Record<string, SpriteFrame>, animations?: Record<string, AnimationDefinition>): Sprite;
211
+ static fromAseprite(imagePath: string, jsonPath: string): Promise<Sprite>;
212
+ /**
213
+ * Computes the source rectangle for a given frame index within the
214
+ * spritesheet.
215
+ *
216
+ * Frame indices are zero-based and laid out left-to-right,
217
+ * top-to-bottom.
218
+ *
219
+ * @param frame - Zero-based frame index.
220
+ * @returns An `{ x, y, width, height }` rectangle in pixel coordinates
221
+ * relative to the top-left corner of the source image.
222
+ *
223
+ * @example
224
+ * ```ts
225
+ * // For a 4-column sheet, frame 5 → col 1, row 1
226
+ * const rect = sprite.getFrameRect(5);
227
+ * ```
228
+ */
229
+ getFrameRect(frame: number | string): SpriteFrame;
230
+ }
231
+ export {};
232
+ //# sourceMappingURL=sprite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sprite.d.ts","sourceRoot":"","sources":["../../src/core/sprite.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,UAAU,mBAAmB;IAC3B,uDAAuD;IACvD,MAAM,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC5B,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,UAAU,WAAW;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,UAAU,UAAU;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,OAAO,OAAO,MAAM;IACzB,oEAAoE;IAC7D,KAAK,EAAE,gBAAgB,CAAC;IAE/B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACI,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAEpD;;OAEG;IACI,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,CAAC,CAAC;IAEjD;;;;;;;;;;;;;;;;OAgBG;gBAED,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAgBlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,MAAM,CAAC,QAAQ,CACb,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,UAAU,EAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAC/C,MAAM;IAQT;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAqBjC,MAAM,CAAC,SAAS,CACd,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACpC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAC/C,MAAM;WAQI,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6B/E;;;;;;;;;;;;;;;;OAgBG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW;CAOlD"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Deterministic 2-D Perlin noise generator with fractal Brownian motion
3
+ * (fBm) support.
4
+ *
5
+ * Produces smooth, continuous noise suitable for terrain heightmaps,
6
+ * cloud textures, procedural vegetation placement, and other organic
7
+ * patterns. The output is fully reproducible for a given seed.
8
+ *
9
+ * The implementation uses a 256-entry permutation table shuffled by a
10
+ * seeded linear congruential generator (LCG) and Ken Perlin's improved
11
+ * 5th-order fade curve \( 6t^5 - 15t^4 + 10t^3 \).
12
+ *
13
+ * @category Utilities
14
+ * @since 0.1.0
15
+ *
16
+ * @example Basic noise sampling
17
+ * ```ts
18
+ * import { PerlinNoise } from "gamefoo";
19
+ *
20
+ * const noise = new PerlinNoise(42);
21
+ * const value = noise.noise2d(1.5, 2.3); // returns a value in [-1, 1]
22
+ * ```
23
+ *
24
+ * @example Generating a heightmap with fBm
25
+ * ```ts
26
+ * const noise = new PerlinNoise(12345);
27
+ * const map: number[][] = [];
28
+ *
29
+ * for (let y = 0; y < 128; y++) {
30
+ * map[y] = [];
31
+ * for (let x = 0; x < 128; x++) {
32
+ * map[y][x] = noise.fbm(x * 0.05, y * 0.05, 6, 2, 0.5);
33
+ * }
34
+ * }
35
+ * ```
36
+ *
37
+ * @example Seeded reproducibility
38
+ * ```ts
39
+ * const a = new PerlinNoise(7);
40
+ * const b = new PerlinNoise(7);
41
+ * console.log(a.noise2d(3, 4) === b.noise2d(3, 4)); // true
42
+ * ```
43
+ */
44
+ export declare class PerlinNoise {
45
+ /**
46
+ * Doubled permutation table (512 entries) used for gradient hashing.
47
+ * Built from a 256-entry shuffle of `[0..255]` seeded by the LCG.
48
+ */
49
+ private perm;
50
+ /**
51
+ * Creates a new noise generator with the given seed.
52
+ *
53
+ * @param seed - An integer seed for the internal LCG. Identical seeds
54
+ * produce identical noise fields.
55
+ *
56
+ * @defaultValue `0`
57
+ */
58
+ constructor(seed?: number);
59
+ /**
60
+ * Ken Perlin's improved 5th-order fade (smoothstep) curve:
61
+ * \( 6t^5 - 15t^4 + 10t^3 \).
62
+ *
63
+ * @param t - Value in `[0, 1]`.
64
+ * @returns Smoothed value in `[0, 1]`.
65
+ *
66
+ * @internal
67
+ */
68
+ private fade;
69
+ /**
70
+ * Standard linear interpolation.
71
+ *
72
+ * @param a - Start value.
73
+ * @param b - End value.
74
+ * @param t - Interpolant in `[0, 1]`.
75
+ * @returns Interpolated value.
76
+ *
77
+ * @internal
78
+ */
79
+ private lerp;
80
+ /**
81
+ * Computes a pseudo-random gradient dot product from a hash and
82
+ * 2-D offset.
83
+ *
84
+ * Uses the bottom 2 bits of `hash` to select one of four gradient
85
+ * directions.
86
+ *
87
+ * @param hash - Permutation table entry.
88
+ * @param x - X offset from the grid point.
89
+ * @param y - Y offset from the grid point.
90
+ * @returns Dot product of the gradient and offset vectors.
91
+ *
92
+ * @internal
93
+ */
94
+ private grad;
95
+ /**
96
+ * Samples 2-D Perlin noise at the given coordinates.
97
+ *
98
+ * @param x - X coordinate (any real number).
99
+ * @param y - Y coordinate (any real number).
100
+ * @returns A noise value in the range `[-1, 1]`.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const n = noise.noise2d(0.5, 0.5);
105
+ * // n is a smooth, deterministic value in [-1, 1]
106
+ * ```
107
+ */
108
+ noise2d(x: number, y: number): number;
109
+ /**
110
+ * Computes fractal Brownian motion (fBm) by layering multiple
111
+ * octaves of {@link PerlinNoise.noise2d} with increasing frequency
112
+ * and decreasing amplitude.
113
+ *
114
+ * The result is normalised to `[-1, 1]`.
115
+ *
116
+ * @param x - X coordinate.
117
+ * @param y - Y coordinate.
118
+ * @param octaves - Number of noise layers to sum.
119
+ * @param lacunarity - Frequency multiplier per octave.
120
+ * @param persistence - Amplitude multiplier per octave (controls
121
+ * roughness).
122
+ * @returns A noise value in `[-1, 1]`.
123
+ *
124
+ * @defaultValue octaves = `4`
125
+ * @defaultValue lacunarity = `2`
126
+ * @defaultValue persistence = `0.5`
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * // 6 octaves for high detail:
131
+ * const height = noise.fbm(x * 0.01, y * 0.01, 6, 2.0, 0.5);
132
+ * ```
133
+ */
134
+ fbm(x: number, y: number, octaves?: number, lacunarity?: number, persistence?: number): number;
135
+ }
136
+ //# sourceMappingURL=perlin_noise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perlin_noise.d.ts","sourceRoot":"","sources":["../../../src/core/utils/perlin_noise.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBAAa,WAAW;IACtB;;;OAGG;IACH,OAAO,CAAC,IAAI,CAAa;IAEzB;;;;;;;OAOG;gBACS,IAAI,GAAE,MAAU;IAgB5B;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI;IAIZ;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAI;IAIZ;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,IAAI;IAOZ;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM;IAoBrC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,SAAI,EAAE,UAAU,SAAI,EAAE,WAAW,SAAM,GAAG,MAAM;CAelF"}
@@ -1,14 +1,161 @@
1
1
  import type { Collidable } from "./behaviours/collidable";
2
+ /**
3
+ * Spatial collision-detection world.
4
+ *
5
+ * `World` maintains a set of {@link Collidable} behaviours and, each
6
+ * frame, performs an **O(n^2)** broad-phase + narrow-phase pass via
7
+ * {@link World.detect}. It supports:
8
+ *
9
+ * - **Layer filtering** — only colliders on the same layer are tested.
10
+ * - **Tag-based interest** — a collider only receives callbacks for
11
+ * tags it has opted into via `collidesWith`.
12
+ * - **Shape combinations** — AABB vs AABB, circle vs circle, and
13
+ * circle vs AABB.
14
+ * - **Solid overlap resolution** — when both colliders are marked
15
+ * `solid`, entities are pushed apart along the axis of least
16
+ * penetration.
17
+ * - **Fixed bodies** — colliders flagged `fixed` are immovable; the
18
+ * other body absorbs the full push.
19
+ *
20
+ * @category Core
21
+ * @since 0.1.0
22
+ *
23
+ * @example Registering colliders
24
+ * ```ts
25
+ * const world = new World();
26
+ *
27
+ * const collidable = new Collidable(entity, world, {
28
+ * shape: { type: "aabb", width: 32, height: 32 },
29
+ * layer: 0,
30
+ * tags: new Set(["enemy"]),
31
+ * solid: true,
32
+ * collidesWith: new Set(["player", "bullet"]),
33
+ * });
34
+ *
35
+ * entity.attachBehaviour(collidable); // calls world.register internally
36
+ * ```
37
+ *
38
+ * @example Running detection manually
39
+ * ```ts
40
+ * world.detect(); // typically called by Engine.update each frame
41
+ * ```
42
+ *
43
+ * @see {@link Collidable} — the behaviour that plugs into this world
44
+ * @see {@link Engine} — calls {@link World.detect} every frame
45
+ */
2
46
  export default class World {
47
+ /**
48
+ * The live set of all registered {@link Collidable} behaviours.
49
+ */
3
50
  private colliders;
51
+ /**
52
+ * Adds a collider to the world so it participates in future
53
+ * {@link World.detect} passes.
54
+ *
55
+ * Called automatically by {@link Collidable.onAttach}.
56
+ *
57
+ * @param collider - The collidable behaviour to register.
58
+ */
4
59
  register(collider: Collidable): void;
60
+ /**
61
+ * Removes a collider from the world.
62
+ *
63
+ * Called automatically by {@link Collidable.onDetach}.
64
+ *
65
+ * @param collider - The collidable behaviour to remove.
66
+ */
5
67
  unregister(collider: Collidable): void;
68
+ /**
69
+ * Runs one full collision-detection pass over every registered
70
+ * collider.
71
+ *
72
+ * **Algorithm:**
73
+ *
74
+ * 1. Iterate all unique pairs `(i, j)` where `i < j`.
75
+ * 2. Skip disabled colliders or mismatched layers.
76
+ * 3. Check tag interest in both directions.
77
+ * 4. Compute world bounds and test intersection.
78
+ * 5. If both are `solid`, resolve the overlap.
79
+ * 6. Fire `onCollision` callbacks on interested sides.
80
+ *
81
+ * @since 0.1.0
82
+ */
6
83
  detect(): void;
84
+ /**
85
+ * Returns `true` if any tag in `wants` exists in `has`.
86
+ *
87
+ * @param wants - Tags the collider is interested in.
88
+ * @param has - Tags the other collider owns.
89
+ * @returns Whether at least one tag overlaps.
90
+ *
91
+ * @internal
92
+ */
7
93
  private tagsOverlap;
94
+ /**
95
+ * Dispatches to the correct narrow-phase test based on collider
96
+ * shape types.
97
+ *
98
+ * Supports AABB-vs-AABB, circle-vs-circle, and circle-vs-AABB.
99
+ *
100
+ * @param a - First collidable.
101
+ * @param boundsA - World bounds of `a`.
102
+ * @param b - Second collidable.
103
+ * @param boundsB - World bounds of `b`.
104
+ * @returns `true` if the two shapes overlap.
105
+ *
106
+ * @internal
107
+ */
8
108
  private intersects;
109
+ /**
110
+ * AABB-vs-AABB overlap test.
111
+ *
112
+ * @param a - First bounding rectangle.
113
+ * @param b - Second bounding rectangle.
114
+ * @returns `true` if the rectangles overlap.
115
+ *
116
+ * @internal
117
+ */
9
118
  private aabbVSAabb;
119
+ /**
120
+ * Circle-vs-circle overlap test using squared-distance comparison
121
+ * (avoids `Math.sqrt`).
122
+ *
123
+ * @param a - First collidable (must have `circle` shape).
124
+ * @param boundsA - World bounds of `a`.
125
+ * @param b - Second collidable (must have `circle` shape).
126
+ * @param boundsB - World bounds of `b`.
127
+ * @returns `true` if the circles overlap.
128
+ *
129
+ * @internal
130
+ */
10
131
  private circleVSCircle;
132
+ /**
133
+ * Circle-vs-AABB overlap test. Finds the closest point on the
134
+ * rectangle to the circle centre and checks the squared distance.
135
+ *
136
+ * @param circle - The collidable with a `circle` shape.
137
+ * @param circleBounds - World bounds of the circle collider.
138
+ * @param rect - World bounds of the AABB collider.
139
+ * @returns `true` if the circle and rectangle overlap.
140
+ *
141
+ * @internal
142
+ */
11
143
  private circleVSAAabb;
144
+ /**
145
+ * Resolves positional overlap between two solid colliders by pushing
146
+ * their owning entities apart along the axis of minimum penetration.
147
+ *
148
+ * Respects the `fixed` flag: if one collider is fixed the other
149
+ * absorbs the full displacement; if both are fixed, no resolution
150
+ * occurs.
151
+ *
152
+ * @param a - First collidable.
153
+ * @param boundsA - World bounds of `a`.
154
+ * @param b - Second collidable.
155
+ * @param boundsB - World bounds of `b`.
156
+ *
157
+ * @internal
158
+ */
12
159
  private resolveOverlap;
13
160
  }
14
161
  //# sourceMappingURL=world.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../core/world.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB,OAAO,CAAC,SAAS,CAA8B;IAE/C,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAIpC,UAAU,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAItC,MAAM,IAAI,IAAI;IA+Cd,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,cAAc;CA4CvB"}
1
+ {"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../src/core/world.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB;;OAEG;IACH,OAAO,CAAC,SAAS,CAA8B;IAE/C;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAIpC;;;;;;OAMG;IACH,UAAU,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAItC;;;;;;;;;;;;;;OAcG;IACH,MAAM,IAAI,IAAI;IA6Ed;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;IAOnB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,UAAU;IAiBlB;;;;;;;;OAQG;IACH,OAAO,CAAC,UAAU;IAIlB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,aAAa;IAerB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,cAAc;CAiCvB"}