like2d 2.8.0 → 2.9.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 (77) hide show
  1. package/README.md +34 -35
  2. package/dist/core/audio.d.ts +12 -9
  3. package/dist/core/audio.d.ts.map +1 -1
  4. package/dist/core/audio.js +7 -4
  5. package/dist/core/canvas.d.ts +58 -0
  6. package/dist/core/canvas.d.ts.map +1 -0
  7. package/dist/core/canvas.js +209 -0
  8. package/dist/core/events.d.ts +91 -13
  9. package/dist/core/events.d.ts.map +1 -1
  10. package/dist/core/events.js +20 -0
  11. package/dist/core/gamepad-mapping.d.ts +57 -18
  12. package/dist/core/gamepad-mapping.d.ts.map +1 -1
  13. package/dist/core/gamepad-mapping.js +23 -223
  14. package/dist/core/gamepad.d.ts +34 -58
  15. package/dist/core/gamepad.d.ts.map +1 -1
  16. package/dist/core/gamepad.js +79 -213
  17. package/dist/core/graphics.d.ts +175 -65
  18. package/dist/core/graphics.d.ts.map +1 -1
  19. package/dist/core/graphics.js +294 -202
  20. package/dist/core/input-state.d.ts +2 -2
  21. package/dist/core/input-state.d.ts.map +1 -1
  22. package/dist/core/input.d.ts +22 -15
  23. package/dist/core/input.d.ts.map +1 -1
  24. package/dist/core/input.js +25 -37
  25. package/dist/core/keyboard.d.ts +6 -7
  26. package/dist/core/keyboard.d.ts.map +1 -1
  27. package/dist/core/keyboard.js +15 -35
  28. package/dist/core/like.d.ts +98 -44
  29. package/dist/core/like.d.ts.map +1 -1
  30. package/dist/core/like.js +8 -0
  31. package/dist/core/mouse.d.ts +31 -24
  32. package/dist/core/mouse.d.ts.map +1 -1
  33. package/dist/core/mouse.js +59 -99
  34. package/dist/core/timer.d.ts +2 -5
  35. package/dist/core/timer.d.ts.map +1 -1
  36. package/dist/core/timer.js +2 -14
  37. package/dist/engine.d.ts +61 -16
  38. package/dist/engine.d.ts.map +1 -1
  39. package/dist/engine.js +121 -160
  40. package/dist/index.d.ts +42 -21
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +35 -14
  43. package/dist/math/index.d.ts +2 -0
  44. package/dist/math/index.d.ts.map +1 -0
  45. package/dist/math/index.js +1 -0
  46. package/dist/math/rect.d.ts +71 -0
  47. package/dist/math/rect.d.ts.map +1 -0
  48. package/dist/{core → math}/rect.js +8 -0
  49. package/dist/math/vector2.d.ts +78 -0
  50. package/dist/math/vector2.d.ts.map +1 -0
  51. package/dist/{core → math}/vector2.js +24 -0
  52. package/dist/prefab-scenes/index.d.ts +7 -0
  53. package/dist/prefab-scenes/index.d.ts.map +1 -0
  54. package/dist/prefab-scenes/index.js +6 -0
  55. package/dist/prefab-scenes/startScreen.d.ts +59 -0
  56. package/dist/prefab-scenes/startScreen.d.ts.map +1 -0
  57. package/dist/{scenes/startup.js → prefab-scenes/startScreen.js} +48 -8
  58. package/dist/scene.d.ts +103 -5
  59. package/dist/scene.d.ts.map +1 -1
  60. package/dist/scene.js +28 -1
  61. package/package.json +18 -2
  62. package/dist/core/canvas-config.d.ts +0 -22
  63. package/dist/core/canvas-config.d.ts.map +0 -1
  64. package/dist/core/canvas-config.js +0 -14
  65. package/dist/core/canvas-manager.d.ts +0 -32
  66. package/dist/core/canvas-manager.d.ts.map +0 -1
  67. package/dist/core/canvas-manager.js +0 -179
  68. package/dist/core/gamepad-buttons.d.ts +0 -23
  69. package/dist/core/gamepad-buttons.d.ts.map +0 -1
  70. package/dist/core/gamepad-buttons.js +0 -36
  71. package/dist/core/rect.d.ts +0 -26
  72. package/dist/core/rect.d.ts.map +0 -1
  73. package/dist/core/vector2.d.ts +0 -26
  74. package/dist/core/vector2.d.ts.map +0 -1
  75. package/dist/gamecontrollerdb.txt +0 -2221
  76. package/dist/scenes/startup.d.ts +0 -18
  77. package/dist/scenes/startup.d.ts.map +0 -1
@@ -1,149 +1,94 @@
1
+ import { Vec2 } from '../math/vector2';
2
+ const mouseButtons = ["left", "middle", "right"];
3
+ const numToButton = (i) => mouseButtons[i];
1
4
  /**
2
5
  * Mouse input handling. Bound to canvas. Emits relative movement when pointer locked.
3
6
  * Buttons: 1 = left, 2 = middle, 3 = right.
4
7
  */
5
- export class Mouse {
6
- constructor(canvas, transformFn) {
7
- Object.defineProperty(this, "x", {
8
- enumerable: true,
9
- configurable: true,
10
- writable: true,
11
- value: 0
12
- });
13
- Object.defineProperty(this, "y", {
14
- enumerable: true,
15
- configurable: true,
16
- writable: true,
17
- value: 0
18
- });
19
- Object.defineProperty(this, "buttons", {
20
- enumerable: true,
21
- configurable: true,
22
- writable: true,
23
- value: new Set()
24
- });
25
- Object.defineProperty(this, "cursorVisible", {
26
- enumerable: true,
27
- configurable: true,
28
- writable: true,
29
- value: true
30
- });
31
- Object.defineProperty(this, "onMouseMove", {
32
- enumerable: true,
33
- configurable: true,
34
- writable: true,
35
- value: void 0
36
- });
37
- Object.defineProperty(this, "onMouseDown", {
38
- enumerable: true,
39
- configurable: true,
40
- writable: true,
41
- value: void 0
42
- });
43
- Object.defineProperty(this, "onMouseUp", {
8
+ export class MouseInternal {
9
+ constructor(canvas, dispatch) {
10
+ Object.defineProperty(this, "canvas", {
44
11
  enumerable: true,
45
12
  configurable: true,
46
13
  writable: true,
47
- value: void 0
14
+ value: canvas
48
15
  });
49
- Object.defineProperty(this, "transformFn", {
16
+ Object.defineProperty(this, "dispatch", {
50
17
  enumerable: true,
51
18
  configurable: true,
52
19
  writable: true,
53
- value: void 0
20
+ value: dispatch
54
21
  });
55
- Object.defineProperty(this, "canvas", {
22
+ Object.defineProperty(this, "pos", {
56
23
  enumerable: true,
57
24
  configurable: true,
58
25
  writable: true,
59
- value: null
26
+ value: [0, 0]
60
27
  });
61
- // Event handler references for cleanup
62
- Object.defineProperty(this, "mousemoveHandler", {
28
+ Object.defineProperty(this, "lastPos", {
63
29
  enumerable: true,
64
30
  configurable: true,
65
31
  writable: true,
66
- value: void 0
32
+ value: [0, 0]
67
33
  });
68
- Object.defineProperty(this, "mousedownHandler", {
34
+ Object.defineProperty(this, "buttons", {
69
35
  enumerable: true,
70
36
  configurable: true,
71
37
  writable: true,
72
- value: void 0
38
+ value: new Set()
73
39
  });
74
- Object.defineProperty(this, "mouseupHandler", {
40
+ Object.defineProperty(this, "cursorVisible", {
75
41
  enumerable: true,
76
42
  configurable: true,
77
43
  writable: true,
78
- value: void 0
44
+ value: true
79
45
  });
80
- Object.defineProperty(this, "wheelHandler", {
46
+ Object.defineProperty(this, "abort", {
81
47
  enumerable: true,
82
48
  configurable: true,
83
49
  writable: true,
84
- value: void 0
50
+ value: new AbortController()
85
51
  });
86
- this.canvas = canvas;
87
- this.transformFn = transformFn;
88
- if (this.canvas) {
89
- this.canvas.tabIndex = 0;
90
- }
91
- this.mousemoveHandler = this.handleMouseMove.bind(this);
92
- this.mousedownHandler = this.handleMouseDown.bind(this);
93
- this.mouseupHandler = this.handleMouseUp.bind(this);
94
- this.wheelHandler = this.handleWheel.bind(this);
95
- if (this.canvas) {
96
- this.canvas.addEventListener('mousemove', this.mousemoveHandler);
97
- this.canvas.addEventListener('mousedown', this.mousedownHandler);
98
- window.addEventListener('mouseup', this.mouseupHandler);
99
- this.canvas.addEventListener('wheel', this.wheelHandler, { passive: false });
100
- }
101
- }
102
- setTransform(transformFn) {
103
- this.transformFn = transformFn;
52
+ this.canvas.addEventListener('like:mousemoved', this.handleMouseMove.bind(this), { signal: this.abort.signal });
53
+ this.canvas.addEventListener('mousedown', this.handleMouseDown.bind(this), { signal: this.abort.signal });
54
+ window.addEventListener('mouseup', this.handleMouseUp.bind(this), { signal: this.abort.signal });
55
+ this.canvas.addEventListener('wheel', this.handleWheel.bind(this), { passive: false, signal: this.abort.signal });
56
+ this.canvas.addEventListener('mouseleave', () => this.buttons.clear(), { signal: this.abort.signal });
104
57
  }
105
58
  handleMouseMove(e) {
106
59
  if (this.isPointerLocked()) {
107
- // When locked, emit relative movement
108
- this.onMouseMove?.([e.movementX, e.movementY], true);
60
+ /** In pointer-lock mode, simulate a real cursor bounded by the canvas. */
61
+ this.pos = Vec2.clamp(Vec2.add(this.pos, e.detail.delta), [0, 0], e.detail.renderSize);
62
+ this.dispatch('mousemoved', [this.pos, e.detail.delta]);
109
63
  }
110
64
  else {
111
- // Normal mode: track position and emit absolute coords
112
- this.x = e.offsetX;
113
- this.y = e.offsetY;
114
- const pos = this.getPosition();
115
- this.onMouseMove?.(pos, false);
65
+ /** In non-pointer locked mode, calculate deltas ourselves. */
66
+ this.pos = e.detail.pos;
67
+ this.dispatch('mousemoved', [this.pos, Vec2.sub(this.pos, this.lastPos)]);
116
68
  }
69
+ this.lastPos = this.pos;
117
70
  }
118
71
  handleMouseDown(e) {
119
- this.buttons.add(e.button + 1);
120
- const pos = this.transformFn ? this.transformFn(e.offsetX, e.offsetY) : [e.offsetX, e.offsetY];
121
- this.onMouseDown?.(pos, e.button + 1);
72
+ // hack: ignore right clicks because they cause a refocus
73
+ if (!this.isPointerLocked() && e.button == 2)
74
+ return;
75
+ this.buttons.add(numToButton(e.button));
76
+ this.dispatch('mousepressed', [[e.offsetX, e.offsetY], numToButton(e.button)]);
122
77
  this.canvas?.focus();
123
78
  }
124
79
  handleMouseUp(e) {
125
- this.buttons.delete(e.button + 1);
126
- const pos = this.transformFn ? this.transformFn(e.offsetX, e.offsetY) : [e.offsetX, e.offsetY];
127
- this.onMouseUp?.(pos, e.button + 1);
80
+ this.buttons.delete(numToButton(e.button));
81
+ this.dispatch('mousereleased', [[e.offsetX, e.offsetY], numToButton(e.button)]);
128
82
  }
129
83
  handleWheel(e) {
130
84
  e.preventDefault();
131
85
  }
132
- dispose() {
133
- if (this.canvas) {
134
- this.canvas.removeEventListener('mousemove', this.mousemoveHandler);
135
- this.canvas.removeEventListener('mousedown', this.mousedownHandler);
136
- this.canvas.removeEventListener('wheel', this.wheelHandler);
137
- }
138
- window.removeEventListener('mouseup', this.mouseupHandler);
139
- this.buttons.clear();
86
+ _dispose() {
87
+ this.abort.abort();
140
88
  }
141
- /** Mouse position in canvas pixels. */
89
+ /** Mouse position, transformed to canvas pixels. */
142
90
  getPosition() {
143
- if (this.transformFn) {
144
- return this.transformFn(this.x, this.y);
145
- }
146
- return [this.x, this.y];
91
+ return this.pos;
147
92
  }
148
93
  /** Check if button is held. Button 1 = left, 2 = middle, 3 = right. */
149
94
  isDown(button) {
@@ -153,11 +98,26 @@ export class Mouse {
153
98
  getPressedButtons() {
154
99
  return new Set(this.buttons);
155
100
  }
156
- /** True when pointer is locked to canvas. */
101
+ /** True when pointer is locked to canvas.
102
+ * {@link lockPointer}
103
+ */
157
104
  isPointerLocked() {
158
105
  return document.pointerLockElement !== null;
159
106
  }
160
- /** Lock or unlock pointer. When locked, mousemoved emits relative deltas. */
107
+ /**
108
+ * Whether to lock (capture) the pointer.
109
+ *
110
+ * In locked mode, the cursor cannot escape the canvas.
111
+ * It also becomes invisible.
112
+ *
113
+ * Note that event {@link mousemoved} passes both
114
+ * `pos` and `delta`.
115
+ *
116
+ * Though the emulated cursor in locked mode
117
+ * (locked mode doesn't natively track absolute position)
118
+ * may be stuck on canvas edges, the `delta` field always
119
+ * represents mouse movement.
120
+ */
161
121
  lockPointer(locked) {
162
122
  if (!this.canvas)
163
123
  return;
@@ -1,17 +1,14 @@
1
- export declare class Timer {
1
+ export declare class TimerInternal {
2
2
  private currentDelta;
3
3
  private totalTime;
4
4
  private frameCount;
5
5
  private fps;
6
6
  private fpsAccumulator;
7
7
  private sleepUntil;
8
- private sceneStartTime;
9
- update(dt: number): void;
10
- resetSceneTime(): void;
8
+ _update(dt: number): void;
11
9
  getDelta(): number;
12
10
  getFPS(): number;
13
11
  getTime(): number;
14
- getSceneTime(): number;
15
12
  isSleeping(): boolean;
16
13
  sleep(duration: number): void;
17
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"timer.d.ts","sourceRoot":"","sources":["../../src/core/timer.ts"],"names":[],"mappings":"AAAA,qBAAa,KAAK;IAChB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,cAAc,CAAK;IAE3B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAaxB,cAAc,IAAI,IAAI;IAItB,QAAQ,IAAI,MAAM;IAIlB,MAAM,IAAI,MAAM;IAIhB,OAAO,IAAI,MAAM;IAIjB,YAAY,IAAI,MAAM;IAItB,UAAU,IAAI,OAAO;IAUrB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CAG9B"}
1
+ {"version":3,"file":"timer.d.ts","sourceRoot":"","sources":["../../src/core/timer.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAuB;IAEzC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAazB,QAAQ,IAAI,MAAM;IAIlB,MAAM,IAAI,MAAM;IAIhB,OAAO,IAAI,MAAM;IAIjB,UAAU,IAAI,OAAO;IAUrB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CAG9B"}
@@ -1,4 +1,4 @@
1
- export class Timer {
1
+ export class TimerInternal {
2
2
  constructor() {
3
3
  Object.defineProperty(this, "currentDelta", {
4
4
  enumerable: true,
@@ -36,14 +36,8 @@ export class Timer {
36
36
  writable: true,
37
37
  value: null
38
38
  });
39
- Object.defineProperty(this, "sceneStartTime", {
40
- enumerable: true,
41
- configurable: true,
42
- writable: true,
43
- value: 0
44
- });
45
39
  }
46
- update(dt) {
40
+ _update(dt) {
47
41
  this.currentDelta = dt;
48
42
  this.totalTime += dt;
49
43
  this.frameCount++;
@@ -54,9 +48,6 @@ export class Timer {
54
48
  this.fpsAccumulator = 0;
55
49
  }
56
50
  }
57
- resetSceneTime() {
58
- this.sceneStartTime = this.totalTime;
59
- }
60
51
  getDelta() {
61
52
  return this.currentDelta;
62
53
  }
@@ -66,9 +57,6 @@ export class Timer {
66
57
  getTime() {
67
58
  return this.totalTime;
68
59
  }
69
- getSceneTime() {
70
- return this.totalTime - this.sceneStartTime;
71
- }
72
60
  isSleeping() {
73
61
  if (this.sleepUntil === null)
74
62
  return false;
package/dist/engine.d.ts CHANGED
@@ -1,25 +1,70 @@
1
- import type { Like2DEvent } from './core/events';
2
- import type { PartialCanvasMode } from './core/canvas-config';
3
- import type { Like } from './core/like';
1
+ /**
2
+ * @module engine
3
+ * @description Core game engine - lifecycle management and event dispatch.
4
+ *
5
+ * You've reached the most evil part of the codebase -- the man
6
+ * behind the curtain.
7
+ *
8
+ * The secret force gluing everything together.
9
+ *
10
+ * If you want to use modules independently, look here first.
11
+ *
12
+ * ## Memory Management
13
+ *
14
+ * Always call `dispose()` when destroying an engine instance:
15
+ * - Removes all event listeners
16
+ * - Stops the game loop
17
+ * - Removes canvas from DOM
18
+ * - Cleans up canvas manager resources
19
+ *
20
+ */
21
+ import type { LikeInternal } from './core/like';
22
+ export type EngineDispatch = Engine["dispatch"];
23
+ /**
24
+ * Core game engine managing the event loop and subsystems.
25
+ *
26
+ * Normally you don't instantiate this directly - use {@link createLike} instead.
27
+ * The Engine class is exposed for advanced use cases like testing or
28
+ * custom initialization sequences.
29
+ *
30
+ * All subsystems are accessible via the {@link like} property.
31
+ */
4
32
  export declare class Engine {
33
+ private container;
5
34
  private canvas;
6
35
  private isRunning;
7
36
  private lastTime;
8
- private container;
9
- private canvasManager;
10
- private handleEvent;
11
- private currentScene;
12
- private gfxState;
13
- private windowFocusHandler;
14
- private windowBlurHandler;
15
- private canvasFocusHandler;
16
- private canvasBlurHandler;
17
- private fullscreenChangeHandler;
18
- readonly like: Like;
37
+ private abort;
38
+ /**
39
+ * The Like interface providing access to all engine subsystems.
40
+ * This object is passed to all scene callbacks and game code.
41
+ */
42
+ readonly like: LikeInternal;
19
43
  constructor(container: HTMLElement);
20
44
  private dispatch;
21
- setMode(mode: PartialCanvasMode): void;
22
- start(handleEvent: (event: Like2DEvent) => void): Promise<void>;
45
+ /**
46
+ * Start the game loop.
47
+ *
48
+ * @remarks
49
+ * This method:
50
+ * 1. Dispatches the initial `load` event
51
+ * 2. Starts the requestAnimationFrame loop
52
+ *
53
+ * The engine runs until dispose() is called.
54
+ */
55
+ start(): Promise<void>;
56
+ /**
57
+ * Clean up all resources and stop the engine.
58
+ *
59
+ * @remarks
60
+ * This method:
61
+ * - Stops the game loop
62
+ * - Removes all event listeners (keyboard, mouse, window, fullscreen)
63
+ * - Disposes canvas manager (removes resize observer)
64
+ * - Removes the canvas element from the DOM
65
+ *
66
+ * The engine cannot be restarted after disposal - create a new instance.
67
+ */
23
68
  dispose(): void;
24
69
  }
25
70
  //# sourceMappingURL=engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAIxC,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAA+C;IAClE,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,QAAQ,CAA8B;IAG9C,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,uBAAuB,CAA6B;IAE5D,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;gBAER,SAAS,EAAE,WAAW;IAqFlC,OAAO,CAAC,QAAQ;IAchB,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAUhC,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BrE,OAAO,IAAI,IAAI;CAiBhB"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;AAEhD;;;;;;;;GAQG;AACH,qBAAa,MAAM;IAaL,OAAO,CAAC,SAAS;IAZ7B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAK;IAErB,OAAO,CAAC,KAAK,CAAyB;IAEtC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;gBAER,SAAS,EAAE,WAAW;IAmD1C,OAAO,CAAC,QAAQ;IAShB;;;;;;;;;OASG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B5B;;;;;;;;;;;OAWG;IACH,OAAO,IAAI,IAAI;CAahB"}