like2d 1.0.0 → 2.0.1

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 (99) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +74 -42
  3. package/assets/logo-banner.svg +188 -0
  4. package/assets/logo-icon.svg +88 -0
  5. package/assets/logo.svg +188 -0
  6. package/dist/adapters/callback/index.d.ts +43 -0
  7. package/dist/adapters/callback/index.d.ts.map +1 -0
  8. package/dist/adapters/callback/index.js +80 -0
  9. package/dist/adapters/scene/index.d.ts +42 -0
  10. package/dist/adapters/scene/index.d.ts.map +1 -0
  11. package/dist/adapters/scene/index.js +112 -0
  12. package/dist/adapters/scene/scene.d.ts +18 -0
  13. package/dist/adapters/scene/scene.d.ts.map +1 -0
  14. package/dist/adapters/scene/startup-scene.d.ts +17 -0
  15. package/dist/adapters/scene/startup-scene.d.ts.map +1 -0
  16. package/dist/adapters/scene/startup-scene.js +41 -0
  17. package/dist/core/audio.d.ts +61 -0
  18. package/dist/core/audio.d.ts.map +1 -0
  19. package/dist/core/audio.js +226 -0
  20. package/dist/core/canvas-config.d.ts +22 -0
  21. package/dist/core/canvas-config.d.ts.map +1 -0
  22. package/dist/core/canvas-config.js +14 -0
  23. package/dist/core/canvas-manager.d.ts +26 -0
  24. package/dist/core/canvas-manager.d.ts.map +1 -0
  25. package/dist/core/canvas-manager.js +197 -0
  26. package/dist/core/events.d.ts +52 -0
  27. package/dist/core/events.d.ts.map +1 -0
  28. package/dist/core/gamepad-button-map.d.ts.map +1 -0
  29. package/dist/core/gamepad-buttons.d.ts +23 -0
  30. package/dist/core/gamepad-buttons.d.ts.map +1 -0
  31. package/dist/core/gamepad-buttons.js +36 -0
  32. package/dist/core/gamepad-db.d.ts.map +1 -0
  33. package/dist/{gamepad-mapping.d.ts → core/gamepad-mapping.d.ts} +3 -15
  34. package/dist/core/gamepad-mapping.d.ts.map +1 -0
  35. package/dist/core/gamepad-mapping.js +223 -0
  36. package/dist/{gamepad.d.ts → core/gamepad.d.ts} +22 -17
  37. package/dist/core/gamepad.d.ts.map +1 -0
  38. package/dist/{gamepad.js → core/gamepad.js} +91 -70
  39. package/dist/{graphics.d.ts → core/graphics.d.ts} +2 -8
  40. package/dist/core/graphics.d.ts.map +1 -0
  41. package/dist/{graphics.js → core/graphics.js} +4 -41
  42. package/dist/core/input-state.d.ts.map +1 -0
  43. package/dist/{input.d.ts → core/input.d.ts} +11 -14
  44. package/dist/core/input.d.ts.map +1 -0
  45. package/dist/{input.js → core/input.js} +31 -41
  46. package/dist/core/keyboard.d.ts +15 -0
  47. package/dist/core/keyboard.d.ts.map +1 -0
  48. package/dist/core/keyboard.js +70 -0
  49. package/dist/core/mouse.d.ts +29 -0
  50. package/dist/core/mouse.d.ts.map +1 -0
  51. package/dist/core/mouse.js +130 -0
  52. package/dist/{rect.d.ts → core/rect.d.ts} +1 -2
  53. package/dist/core/rect.d.ts.map +1 -0
  54. package/dist/{rect.js → core/rect.js} +24 -28
  55. package/dist/{timer.d.ts → core/timer.d.ts} +0 -1
  56. package/dist/core/timer.d.ts.map +1 -0
  57. package/dist/{timer.js → core/timer.js} +0 -1
  58. package/dist/{vector2.d.ts → core/vector2.d.ts} +4 -10
  59. package/dist/core/vector2.d.ts.map +1 -0
  60. package/dist/{vector2.js → core/vector2.js} +40 -40
  61. package/dist/engine.d.ts +42 -0
  62. package/dist/engine.d.ts.map +1 -0
  63. package/dist/engine.js +154 -0
  64. package/dist/index.d.ts +38 -44
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +24 -250
  67. package/package.json +9 -23
  68. package/dist/audio.d.ts +0 -52
  69. package/dist/audio.d.ts.map +0 -1
  70. package/dist/audio.js +0 -250
  71. package/dist/events.d.ts +0 -36
  72. package/dist/events.d.ts.map +0 -1
  73. package/dist/gamepad-button-map.d.ts.map +0 -1
  74. package/dist/gamepad-db.d.ts.map +0 -1
  75. package/dist/gamepad-mapping.d.ts.map +0 -1
  76. package/dist/gamepad-mapping.js +0 -191
  77. package/dist/gamepad.d.ts.map +0 -1
  78. package/dist/graphics.d.ts.map +0 -1
  79. package/dist/input-state.d.ts.map +0 -1
  80. package/dist/input.d.ts.map +0 -1
  81. package/dist/keyboard.d.ts +0 -9
  82. package/dist/keyboard.d.ts.map +0 -1
  83. package/dist/keyboard.js +0 -33
  84. package/dist/mouse.d.ts +0 -20
  85. package/dist/mouse.d.ts.map +0 -1
  86. package/dist/mouse.js +0 -84
  87. package/dist/rect.d.ts.map +0 -1
  88. package/dist/scene.d.ts +0 -10
  89. package/dist/scene.d.ts.map +0 -1
  90. package/dist/timer.d.ts.map +0 -1
  91. package/dist/vector2.d.ts.map +0 -1
  92. /package/dist/{scene.js → adapters/scene/scene.js} +0 -0
  93. /package/dist/{events.js → core/events.js} +0 -0
  94. /package/dist/{gamepad-button-map.d.ts → core/gamepad-button-map.d.ts} +0 -0
  95. /package/dist/{gamepad-button-map.js → core/gamepad-button-map.js} +0 -0
  96. /package/dist/{gamepad-db.d.ts → core/gamepad-db.d.ts} +0 -0
  97. /package/dist/{gamepad-db.js → core/gamepad-db.js} +0 -0
  98. /package/dist/{input-state.d.ts → core/input-state.d.ts} +0 -0
  99. /package/dist/{input-state.js → core/input-state.js} +0 -0
@@ -1,35 +1,41 @@
1
- import { getButtonName, getButtonIndex } from './gamepad-button-map';
1
+ import { getGPName, GP } from './gamepad-buttons';
2
2
  import { ButtonMapping } from './gamepad-mapping';
3
- export { getButtonName, getButtonIndex };
4
- export interface GamepadButtonEvent {
5
- gamepadIndex: number;
6
- buttonIndex: number;
7
- buttonName: string;
8
- rawButtonIndex: number;
9
- }
3
+ export { GP, getGPName };
10
4
  export interface StickPosition {
11
5
  x: number;
12
6
  y: number;
13
7
  }
8
+ export type ButtonCallback = (gamepadIndex: number, buttonIndex: number, buttonName: string, pressed: boolean) => void;
14
9
  export declare class Gamepad {
15
10
  private buttonTrackers;
16
11
  private connectedGamepads;
17
12
  private buttonMappings;
13
+ onButtonEvent?: (gamepadIndex: number, buttonIndex: number, buttonName: string, pressed: boolean) => void;
14
+ private onConnected?;
15
+ private onDisconnected?;
16
+ private gamepadConnectedHandler;
17
+ private gamepadDisconnectedHandler;
18
+ private blurHandler;
18
19
  constructor();
20
+ private handleGamepadConnected;
21
+ private handleGamepadDisconnected;
22
+ private handleBlur;
23
+ setCallbacks(callbacks: {
24
+ onConnected?: (gamepad: globalThis.Gamepad) => void;
25
+ onDisconnected?: (gamepadIndex: number) => void;
26
+ }): void;
27
+ dispose(): void;
19
28
  init(): Promise<void>;
20
- private extractVendorProduct;
21
- private setupEventListeners;
22
- update(): {
23
- pressed: GamepadButtonEvent[];
24
- released: GamepadButtonEvent[];
25
- };
29
+ private onGamepadConnectedInternal;
30
+ private onGamepadDisconnectedInternal;
31
+ update(): void;
26
32
  isConnected(gamepadIndex: number): boolean;
27
33
  /**
28
34
  * Check if a button is currently pressed on a specific gamepad
29
35
  * Uses mapped button indices (standard layout)
30
36
  */
31
- isButtonDown(gamepadIndex: number, button: number | string): boolean;
32
- isButtonDownOnAny(button: number | string): boolean;
37
+ isButtonDown(gamepadIndex: number, buttonIndex: number): boolean;
38
+ isButtonDownOnAny(buttonIndex: number): boolean;
33
39
  getPressedButtons(gamepadIndex: number): Set<number>;
34
40
  getConnectedGamepads(): number[];
35
41
  /**
@@ -52,5 +58,4 @@ export declare class Gamepad {
52
58
  getLeftStick(gamepadIndex: number): StickPosition;
53
59
  getRightStick(gamepadIndex: number): StickPosition;
54
60
  }
55
- export declare const gamepad: Gamepad;
56
61
  //# sourceMappingURL=gamepad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad.d.ts","sourceRoot":"","sources":["../../src/core/gamepad.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EAAkB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;AAEzB,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAkBD,MAAM,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;AAEvH,qBAAa,OAAO;IAClB,OAAO,CAAC,cAAc,CAAgD;IACtE,OAAO,CAAC,iBAAiB,CAAyC;IAClE,OAAO,CAAC,cAAc,CAAoC;IACnD,aAAa,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjH,OAAO,CAAC,WAAW,CAAC,CAAwC;IAC5D,OAAO,CAAC,cAAc,CAAC,CAAiC;IAGxD,OAAO,CAAC,uBAAuB,CAAuC;IACtE,OAAO,CAAC,0BAA0B,CAAuC;IACzE,OAAO,CAAC,WAAW,CAAa;;IAchC,OAAO,CAAC,sBAAsB;IAK9B,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,UAAU;IAMlB,YAAY,CAAC,SAAS,EAAE;QACtB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,KAAK,IAAI,CAAC;QACpD,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;KACjD,GAAG,IAAI;IAKR,OAAO,IAAI,IAAI;IAST,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,OAAO,CAAC,0BAA0B;IAclC,OAAO,CAAC,6BAA6B;IAMrC,MAAM,IAAI,IAAI;IA4Cd,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAI1C;;;OAGG;IACH,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAKhE,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAO/C,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAKpD,oBAAoB,IAAI,MAAM,EAAE;IAIhC;;OAEG;IACH,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,GAAG,SAAS;IAIhE;;OAEG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIjE;;OAEG;IACH,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAKzC;;OAEG;IACH,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK3D,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAMxD,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa;IAMjD,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa;CAKnD"}
@@ -1,7 +1,7 @@
1
- import { getButtonName, getButtonIndex } from './gamepad-button-map';
1
+ import { getGPName, GP } from './gamepad-buttons';
2
2
  import { InputStateTracker } from './input-state';
3
3
  import { gamepadMapping } from './gamepad-mapping';
4
- export { getButtonName, getButtonIndex };
4
+ export { GP, getGPName };
5
5
  const AXIS_DEADZONE = 0.15;
6
6
  function applyDeadzone(value, deadzone = AXIS_DEADZONE) {
7
7
  if (Math.abs(value) < deadzone)
@@ -37,60 +37,99 @@ export class Gamepad {
37
37
  writable: true,
38
38
  value: new Map()
39
39
  });
40
- this.setupEventListeners();
40
+ Object.defineProperty(this, "onButtonEvent", {
41
+ enumerable: true,
42
+ configurable: true,
43
+ writable: true,
44
+ value: void 0
45
+ });
46
+ Object.defineProperty(this, "onConnected", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: void 0
51
+ });
52
+ Object.defineProperty(this, "onDisconnected", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+ // Event handler references for cleanup
59
+ Object.defineProperty(this, "gamepadConnectedHandler", {
60
+ enumerable: true,
61
+ configurable: true,
62
+ writable: true,
63
+ value: void 0
64
+ });
65
+ Object.defineProperty(this, "gamepadDisconnectedHandler", {
66
+ enumerable: true,
67
+ configurable: true,
68
+ writable: true,
69
+ value: void 0
70
+ });
71
+ Object.defineProperty(this, "blurHandler", {
72
+ enumerable: true,
73
+ configurable: true,
74
+ writable: true,
75
+ value: void 0
76
+ });
77
+ // Bind event handlers
78
+ this.gamepadConnectedHandler = this.handleGamepadConnected.bind(this);
79
+ this.gamepadDisconnectedHandler = this.handleGamepadDisconnected.bind(this);
80
+ this.blurHandler = this.handleBlur.bind(this);
81
+ // Register event listeners
82
+ window.addEventListener('gamepadconnected', this.gamepadConnectedHandler);
83
+ window.addEventListener('gamepaddisconnected', this.gamepadDisconnectedHandler);
84
+ window.addEventListener('blur', this.blurHandler);
85
+ }
86
+ handleGamepadConnected(e) {
87
+ this.onGamepadConnectedInternal(e.gamepad);
88
+ this.onConnected?.(e.gamepad);
89
+ }
90
+ handleGamepadDisconnected(e) {
91
+ this.onGamepadDisconnectedInternal(e.gamepad.index);
92
+ this.onDisconnected?.(e.gamepad.index);
93
+ }
94
+ handleBlur() {
95
+ for (const tracker of this.buttonTrackers.values()) {
96
+ tracker.clear();
97
+ }
98
+ }
99
+ setCallbacks(callbacks) {
100
+ this.onConnected = callbacks.onConnected;
101
+ this.onDisconnected = callbacks.onDisconnected;
102
+ }
103
+ dispose() {
104
+ window.removeEventListener('gamepadconnected', this.gamepadConnectedHandler);
105
+ window.removeEventListener('gamepaddisconnected', this.gamepadDisconnectedHandler);
106
+ window.removeEventListener('blur', this.blurHandler);
107
+ this.connectedGamepads.clear();
108
+ this.buttonTrackers.clear();
109
+ this.buttonMappings.clear();
41
110
  }
42
111
  async init() {
43
112
  await gamepadMapping.loadDatabase();
44
113
  }
45
- extractVendorProduct(gamepad) {
46
- const id = gamepad.id;
47
- const vendorProductMatch = id.match(/Vendor:\s*([0-9a-fA-F]+)\s+Product:\s*([0-9a-fA-F]+)/i);
48
- if (vendorProductMatch) {
49
- const vendor = parseInt(vendorProductMatch[1], 16);
50
- const product = parseInt(vendorProductMatch[2], 16);
51
- if (!isNaN(vendor) && !isNaN(product)) {
52
- return { vendor, product };
53
- }
54
- }
55
- const hexMatch = id.match(/^([0-9a-fA-F]{4})[\s-]+([0-9a-fA-F]{4})/);
56
- if (hexMatch) {
57
- const vendor = parseInt(hexMatch[1], 16);
58
- const product = parseInt(hexMatch[2], 16);
59
- if (!isNaN(vendor) && !isNaN(product)) {
60
- return { vendor, product };
61
- }
114
+ onGamepadConnectedInternal(gamepad) {
115
+ this.connectedGamepads.set(gamepad.index, gamepad);
116
+ this.buttonTrackers.set(gamepad.index, new InputStateTracker());
117
+ const mapping = gamepadMapping.getMapping(gamepad);
118
+ this.buttonMappings.set(gamepad.index, mapping);
119
+ console.log(`[Gamepad] Connected: "${gamepad.id}"`);
120
+ if (mapping.vendor !== null && mapping.product !== null) {
121
+ console.log(`[Gamepad] Vendor: 0x${mapping.vendor.toString(16).padStart(4, '0')}, Product: 0x${mapping.product.toString(16).padStart(4, '0')}`);
62
122
  }
63
- return null;
64
- }
65
- setupEventListeners() {
66
- window.addEventListener('gamepadconnected', (e) => {
67
- this.connectedGamepads.set(e.gamepad.index, e.gamepad);
68
- this.buttonTrackers.set(e.gamepad.index, new InputStateTracker());
69
- const mapping = gamepadMapping.getMapping(e.gamepad);
70
- this.buttonMappings.set(e.gamepad.index, mapping);
71
- console.log(`[Gamepad] Connected: "${e.gamepad.id}"`);
72
- const vp = this.extractVendorProduct(e.gamepad);
73
- if (vp) {
74
- console.log(`[Gamepad] Vendor: 0x${vp.vendor.toString(16).padStart(4, '0')}, Product: 0x${vp.product.toString(16).padStart(4, '0')}`);
75
- }
76
- const mappingType = e.gamepad.mapping === 'standard' ? 'browser standard' : (mapping.hasMapping ? 'SDL DB' : 'unmapped');
77
- console.log(`[Gamepad] Mapped as: "${mapping.controllerName}" (${mappingType})`);
78
- });
79
- window.addEventListener('gamepaddisconnected', (e) => {
80
- this.connectedGamepads.delete(e.gamepad.index);
81
- this.buttonTrackers.delete(e.gamepad.index);
82
- this.buttonMappings.delete(e.gamepad.index);
83
- });
84
- window.addEventListener('blur', () => {
85
- for (const tracker of this.buttonTrackers.values()) {
86
- tracker.clear();
87
- }
88
- });
123
+ const mappingType = gamepad.mapping === 'standard' ? 'browser standard' : (mapping.hasMapping ? 'SDL DB' : 'unmapped');
124
+ console.log(`[Gamepad] Mapped as: "${mapping.controllerName}" (${mappingType})`);
125
+ }
126
+ onGamepadDisconnectedInternal(gamepadIndex) {
127
+ this.connectedGamepads.delete(gamepadIndex);
128
+ this.buttonTrackers.delete(gamepadIndex);
129
+ this.buttonMappings.delete(gamepadIndex);
89
130
  }
90
131
  update() {
91
132
  const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];
92
- const pressed = [];
93
- const released = [];
94
133
  for (let i = 0; i < gamepads.length; i++) {
95
134
  const gamepad = gamepads[i];
96
135
  if (gamepad) {
@@ -118,24 +157,13 @@ export class Gamepad {
118
157
  }
119
158
  const changes = tracker.update(pressedButtons);
120
159
  for (const buttonIndex of changes.justPressed) {
121
- pressed.push({
122
- gamepadIndex: i,
123
- buttonIndex,
124
- buttonName: getButtonName(buttonIndex),
125
- rawButtonIndex: mapping.fromStandard.get(buttonIndex) ?? buttonIndex,
126
- });
160
+ this.onButtonEvent?.(i, buttonIndex, getGPName(buttonIndex), true);
127
161
  }
128
162
  for (const buttonIndex of changes.justReleased) {
129
- released.push({
130
- gamepadIndex: i,
131
- buttonIndex,
132
- buttonName: getButtonName(buttonIndex),
133
- rawButtonIndex: mapping.fromStandard.get(buttonIndex) ?? buttonIndex,
134
- });
163
+ this.onButtonEvent?.(i, buttonIndex, getGPName(buttonIndex), false);
135
164
  }
136
165
  }
137
166
  }
138
- return { pressed, released };
139
167
  }
140
168
  isConnected(gamepadIndex) {
141
169
  return this.connectedGamepads.has(gamepadIndex);
@@ -144,17 +172,11 @@ export class Gamepad {
144
172
  * Check if a button is currently pressed on a specific gamepad
145
173
  * Uses mapped button indices (standard layout)
146
174
  */
147
- isButtonDown(gamepadIndex, button) {
148
- const buttonIndex = typeof button === 'string' ? getButtonIndex(button) : button;
149
- if (buttonIndex === undefined)
150
- return false;
175
+ isButtonDown(gamepadIndex, buttonIndex) {
151
176
  const tracker = this.buttonTrackers.get(gamepadIndex);
152
177
  return tracker ? tracker.isDown(buttonIndex) : false;
153
178
  }
154
- isButtonDownOnAny(button) {
155
- const buttonIndex = typeof button === 'string' ? getButtonIndex(button) : button;
156
- if (buttonIndex === undefined)
157
- return false;
179
+ isButtonDownOnAny(buttonIndex) {
158
180
  for (const tracker of this.buttonTrackers.values()) {
159
181
  if (tracker.isDown(buttonIndex))
160
182
  return true;
@@ -213,4 +235,3 @@ export class Gamepad {
213
235
  return applyRadialDeadzone(gamepad.axes[2], gamepad.axes[3]);
214
236
  }
215
237
  }
216
- export const gamepad = new Gamepad();
@@ -40,12 +40,12 @@ export declare class ImageHandle {
40
40
  }
41
41
  export declare class Graphics {
42
42
  private ctx;
43
- private screenCtx;
43
+ private readonly screenCtx;
44
44
  private canvases;
45
45
  private backgroundColor;
46
46
  private images;
47
47
  private defaultFont;
48
- setContext(ctx: CanvasRenderingContext2D | null): void;
48
+ constructor(ctx: CanvasRenderingContext2D);
49
49
  private applyColor;
50
50
  private setStrokeProps;
51
51
  clear(): void;
@@ -63,11 +63,6 @@ export declare class Graphics {
63
63
  getFont(): string;
64
64
  newImage(path: string): ImageHandle;
65
65
  draw(handle: ImageHandle, position: Vector2, props?: DrawProps): void;
66
- push(): void;
67
- pop(): void;
68
- translate(delta: Vector2): void;
69
- rotate(angle: number): void;
70
- scale(s: number | Vector2): void;
71
66
  getCanvasSize(): Vector2;
72
67
  newCanvas(size: Vector2): Canvas;
73
68
  setCanvas(canvas?: Canvas | null): void;
@@ -76,5 +71,4 @@ export declare class Graphics {
76
71
  arc(mode: DrawMode, x: number, y: number, radius: number, angle1: number, angle2: number, props?: ShapeProps): void;
77
72
  points(color: Color, points: Vector2[]): void;
78
73
  }
79
- export declare const graphics: Graphics;
80
74
  //# sourceMappingURL=graphics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphics.d.ts","sourceRoot":"","sources":["../../src/core/graphics.ts"],"names":[],"mappings":"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"}
@@ -59,18 +59,18 @@ function parseColor(color) {
59
59
  return `rgba(${r * 255}, ${g * 255}, ${b * 255}, ${a})`;
60
60
  }
61
61
  export class Graphics {
62
- constructor() {
62
+ constructor(ctx) {
63
63
  Object.defineProperty(this, "ctx", {
64
64
  enumerable: true,
65
65
  configurable: true,
66
66
  writable: true,
67
- value: null
67
+ value: void 0
68
68
  });
69
69
  Object.defineProperty(this, "screenCtx", {
70
70
  enumerable: true,
71
71
  configurable: true,
72
72
  writable: true,
73
- value: null
73
+ value: void 0
74
74
  });
75
75
  Object.defineProperty(this, "canvases", {
76
76
  enumerable: true,
@@ -96,13 +96,9 @@ export class Graphics {
96
96
  writable: true,
97
97
  value: '16px sans-serif'
98
98
  });
99
- }
100
- setContext(ctx) {
101
99
  this.screenCtx = ctx;
102
100
  this.ctx = ctx;
103
- if (ctx) {
104
- ctx.font = this.defaultFont;
105
- }
101
+ ctx.font = this.defaultFont;
106
102
  }
107
103
  applyColor(color) {
108
104
  return parseColor(color ?? [1, 1, 1, 1]);
@@ -269,38 +265,6 @@ export class Graphics {
269
265
  }
270
266
  this.ctx.restore();
271
267
  }
272
- push() {
273
- if (!this.ctx)
274
- return;
275
- this.ctx.save();
276
- }
277
- pop() {
278
- if (!this.ctx)
279
- return;
280
- this.ctx.restore();
281
- }
282
- translate(delta) {
283
- if (!this.ctx)
284
- return;
285
- const [x, y] = delta;
286
- this.ctx.translate(x, y);
287
- }
288
- rotate(angle) {
289
- if (!this.ctx)
290
- return;
291
- this.ctx.rotate(angle);
292
- }
293
- scale(s) {
294
- if (!this.ctx)
295
- return;
296
- if (typeof s === 'number') {
297
- this.ctx.scale(s, s);
298
- }
299
- else {
300
- const [sx, sy] = s;
301
- this.ctx.scale(sx, sy);
302
- }
303
- }
304
268
  getCanvasSize() {
305
269
  const width = this.ctx?.canvas.width ?? 800;
306
270
  const height = this.ctx?.canvas.height ?? 600;
@@ -385,4 +349,3 @@ export class Graphics {
385
349
  points.forEach(([x, y]) => this.ctx.fillRect(x, y, 1, 1));
386
350
  }
387
351
  }
388
- export const graphics = new Graphics();
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-state.d.ts","sourceRoot":"","sources":["../../src/core/input-state.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAiB,CAAC,CAAC;IAC9B,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,SAAS,CAAgB;IAEjC,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG;QAAE,WAAW,EAAE,CAAC,EAAE,CAAC;QAAC,YAAY,EAAE,CAAC,EAAE,CAAA;KAAE;IAuBpE,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIvB,WAAW,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAI5B,YAAY,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAI7B,eAAe,IAAI,GAAG,CAAC,CAAC,CAAC;IAIzB,KAAK,IAAI,IAAI;CAId"}
@@ -1,12 +1,22 @@
1
+ import type { Keyboard } from './keyboard';
2
+ import type { Mouse } from './mouse';
3
+ import type { Gamepad } from './gamepad';
1
4
  export type InputType = 'keyboard' | 'mouse' | 'gamepad';
2
5
  export interface InputBinding {
3
6
  type: InputType;
4
7
  code: string;
5
- gamepadIndex?: number;
6
8
  }
7
9
  export declare class Input {
8
10
  private actionMap;
9
11
  private actionStateTracker;
12
+ private keyboard;
13
+ private mouse;
14
+ private gamepad;
15
+ constructor(deps: {
16
+ keyboard: Keyboard;
17
+ mouse: Mouse;
18
+ gamepad: Gamepad;
19
+ });
10
20
  map(action: string, inputs: string[]): void;
11
21
  unmap(action: string): void;
12
22
  isDown(action: string): boolean;
@@ -15,22 +25,9 @@ export declare class Input {
15
25
  update(): {
16
26
  pressed: string[];
17
27
  released: string[];
18
- gamepadPressed: Array<{
19
- gamepadIndex: number;
20
- buttonIndex: number;
21
- buttonName: string;
22
- rawButtonIndex: number;
23
- }>;
24
- gamepadReleased: Array<{
25
- gamepadIndex: number;
26
- buttonIndex: number;
27
- buttonName: string;
28
- rawButtonIndex: number;
29
- }>;
30
28
  };
31
29
  private parseInput;
32
30
  private isBindingActive;
33
31
  clear(): void;
34
32
  }
35
- export declare const input: Input;
36
33
  //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/core/input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAaD,qBAAa,KAAK;IAChB,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,kBAAkB,CAAmC;IAC7D,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,OAAO,CAAU;gBAEb,IAAI,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,KAAK,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE;IAMxE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAK3C,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK3B,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAO/B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIpC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIrC,MAAM,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE;IAgBnD,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,eAAe;IAuBvB,KAAK,IAAI,IAAI;CAId"}
@@ -1,8 +1,5 @@
1
- import { keyboard } from "./keyboard";
2
- import { mouse } from "./mouse";
3
- import { gamepad } from "./gamepad";
4
1
  import { InputStateTracker } from './input-state';
5
- import { getButtonIndex } from './gamepad-button-map';
2
+ import { GP_NAME_MAP } from './gamepad-buttons';
6
3
  const buttonMap = {
7
4
  'Left': 1,
8
5
  'Right': 3,
@@ -14,7 +11,7 @@ const buttonMap = {
14
11
  '5': 5,
15
12
  };
16
13
  export class Input {
17
- constructor() {
14
+ constructor(deps) {
18
15
  Object.defineProperty(this, "actionMap", {
19
16
  enumerable: true,
20
17
  configurable: true,
@@ -27,6 +24,27 @@ export class Input {
27
24
  writable: true,
28
25
  value: new InputStateTracker()
29
26
  });
27
+ Object.defineProperty(this, "keyboard", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: void 0
32
+ });
33
+ Object.defineProperty(this, "mouse", {
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true,
37
+ value: void 0
38
+ });
39
+ Object.defineProperty(this, "gamepad", {
40
+ enumerable: true,
41
+ configurable: true,
42
+ writable: true,
43
+ value: void 0
44
+ });
45
+ this.keyboard = deps.keyboard;
46
+ this.mouse = deps.mouse;
47
+ this.gamepad = deps.gamepad;
30
48
  }
31
49
  map(action, inputs) {
32
50
  const bindings = inputs.map(input => this.parseInput(input));
@@ -49,7 +67,7 @@ export class Input {
49
67
  return this.actionStateTracker.justReleased(action);
50
68
  }
51
69
  update() {
52
- const { pressed: gamepadPressed, released: gamepadReleased } = gamepad.update();
70
+ this.gamepad.update();
53
71
  const activeActions = new Set();
54
72
  for (const [action] of this.actionMap) {
55
73
  if (this.isDown(action)) {
@@ -57,12 +75,7 @@ export class Input {
57
75
  }
58
76
  }
59
77
  const { justPressed, justReleased } = this.actionStateTracker.update(activeActions);
60
- return {
61
- pressed: justPressed,
62
- released: justReleased,
63
- gamepadPressed,
64
- gamepadReleased,
65
- };
78
+ return { pressed: justPressed, released: justReleased };
66
79
  }
67
80
  parseInput(input) {
68
81
  const normalized = input.trim();
@@ -70,48 +83,26 @@ export class Input {
70
83
  const buttonCode = normalized.replace('Mouse', '');
71
84
  return { type: 'mouse', code: buttonCode };
72
85
  }
73
- if (normalized.startsWith('GP')) {
74
- // Format: GP ButtonBottom, GP LB, GP RT, etc. - any gamepad
75
- // Format: GP0 ButtonBottom, GP1 LB, etc. - specific gamepad
76
- const rest = normalized.slice(2); // Remove "GP" prefix
77
- // Check if there's a gamepad index
78
- const match = rest.match(/^(\d+)\s+(.+)$/);
79
- if (match) {
80
- // Specific gamepad: GP0 ButtonBottom
81
- const gamepadIndex = parseInt(match[1], 10);
82
- const buttonName = match[2].trim();
83
- return { type: 'gamepad', code: buttonName, gamepadIndex };
84
- }
85
- else {
86
- // Any gamepad: GP ButtonBottom
87
- const buttonName = rest.trim();
88
- return { type: 'gamepad', code: buttonName };
89
- }
86
+ if (normalized.startsWith('Button') || normalized.startsWith('DP')) {
87
+ return { type: 'gamepad', code: normalized };
90
88
  }
91
89
  return { type: 'keyboard', code: normalized };
92
90
  }
93
91
  isBindingActive(binding) {
94
92
  switch (binding.type) {
95
93
  case 'keyboard':
96
- return keyboard.isDown(binding.code);
94
+ return this.keyboard.isDown(binding.code);
97
95
  case 'mouse': {
98
96
  const button = buttonMap[binding.code];
99
97
  if (button !== undefined) {
100
- return mouse.isDown(button);
98
+ return this.mouse.isDown(button);
101
99
  }
102
100
  return false;
103
101
  }
104
102
  case 'gamepad': {
105
- const buttonIndex = getButtonIndex(binding.code);
103
+ const buttonIndex = GP_NAME_MAP[binding.code];
106
104
  if (buttonIndex !== undefined) {
107
- if (binding.gamepadIndex !== undefined) {
108
- // Check specific gamepad
109
- return gamepad.isButtonDown(binding.gamepadIndex, buttonIndex);
110
- }
111
- else {
112
- // Check any gamepad
113
- return gamepad.isButtonDownOnAny(buttonIndex);
114
- }
105
+ return this.gamepad.isButtonDownOnAny(buttonIndex);
115
106
  }
116
107
  return false;
117
108
  }
@@ -124,4 +115,3 @@ export class Input {
124
115
  this.actionStateTracker.clear();
125
116
  }
126
117
  }
127
- export const input = new Input();
@@ -0,0 +1,15 @@
1
+ export declare class Keyboard {
2
+ private pressedScancodes;
3
+ onKeyEvent?: (scancode: string, keycode: string, type: 'keydown' | 'keyup') => void;
4
+ private keydownHandler;
5
+ private keyupHandler;
6
+ private blurHandler;
7
+ constructor();
8
+ private handleKeyDown;
9
+ private handleKeyUp;
10
+ private handleBlur;
11
+ dispose(): void;
12
+ isDown(scancode: string): boolean;
13
+ isAnyDown(...scancodes: string[]): boolean;
14
+ }
15
+ //# sourceMappingURL=keyboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/core/keyboard.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAQ;IACnB,OAAO,CAAC,gBAAgB,CAAqB;IACtC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC;IAG3F,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,WAAW,CAAa;;IAchC,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,UAAU;IAIlB,OAAO,IAAI,IAAI;IAOf,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIjC,SAAS,CAAC,GAAG,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO;CAG3C"}
@@ -0,0 +1,70 @@
1
+ export class Keyboard {
2
+ constructor() {
3
+ Object.defineProperty(this, "pressedScancodes", {
4
+ enumerable: true,
5
+ configurable: true,
6
+ writable: true,
7
+ value: new Set()
8
+ });
9
+ Object.defineProperty(this, "onKeyEvent", {
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true,
13
+ value: void 0
14
+ });
15
+ // Event handler references for cleanup
16
+ Object.defineProperty(this, "keydownHandler", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: void 0
21
+ });
22
+ Object.defineProperty(this, "keyupHandler", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
28
+ Object.defineProperty(this, "blurHandler", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: void 0
33
+ });
34
+ // Bind event handlers
35
+ this.keydownHandler = this.handleKeyDown.bind(this);
36
+ this.keyupHandler = this.handleKeyUp.bind(this);
37
+ this.blurHandler = this.handleBlur.bind(this);
38
+ // Register event listeners
39
+ window.addEventListener('keydown', this.keydownHandler);
40
+ window.addEventListener('keyup', this.keyupHandler);
41
+ window.addEventListener('blur', this.blurHandler);
42
+ }
43
+ handleKeyDown(e) {
44
+ if (e.code) {
45
+ this.pressedScancodes.add(e.code);
46
+ }
47
+ this.onKeyEvent?.(e.code, e.key, 'keydown');
48
+ }
49
+ handleKeyUp(e) {
50
+ if (e.code) {
51
+ this.pressedScancodes.delete(e.code);
52
+ }
53
+ this.onKeyEvent?.(e.code, e.key, 'keyup');
54
+ }
55
+ handleBlur() {
56
+ this.pressedScancodes.clear();
57
+ }
58
+ dispose() {
59
+ window.removeEventListener('keydown', this.keydownHandler);
60
+ window.removeEventListener('keyup', this.keyupHandler);
61
+ window.removeEventListener('blur', this.blurHandler);
62
+ this.pressedScancodes.clear();
63
+ }
64
+ isDown(scancode) {
65
+ return this.pressedScancodes.has(scancode);
66
+ }
67
+ isAnyDown(...scancodes) {
68
+ return scancodes.some(code => this.pressedScancodes.has(code));
69
+ }
70
+ }