like2d 2.8.0 → 2.10.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 (122) hide show
  1. package/README.md +44 -41
  2. package/dist/__benchmarks__/vector2.bench.d.ts +2 -0
  3. package/dist/__benchmarks__/vector2.bench.d.ts.map +1 -0
  4. package/dist/__benchmarks__/vector2.bench.js +74 -0
  5. package/dist/{core → audio}/audio.d.ts +21 -9
  6. package/dist/audio/audio.d.ts.map +1 -0
  7. package/dist/{core → audio}/audio.js +15 -4
  8. package/dist/audio/index.d.ts +2 -0
  9. package/dist/audio/index.d.ts.map +1 -0
  10. package/dist/engine.d.ts +30 -15
  11. package/dist/engine.d.ts.map +1 -1
  12. package/dist/engine.js +79 -160
  13. package/dist/events.d.ts +86 -0
  14. package/dist/events.d.ts.map +1 -0
  15. package/dist/events.js +5 -0
  16. package/dist/gamecontrollerdb.txt +9 -8
  17. package/dist/graphics/canvas.d.ts +65 -0
  18. package/dist/graphics/canvas.d.ts.map +1 -0
  19. package/dist/graphics/canvas.js +224 -0
  20. package/dist/graphics/drawing.d.ts +203 -0
  21. package/dist/graphics/drawing.d.ts.map +1 -0
  22. package/dist/graphics/drawing.js +388 -0
  23. package/dist/graphics/index.d.ts +19 -0
  24. package/dist/graphics/index.d.ts.map +1 -0
  25. package/dist/graphics/index.js +13 -0
  26. package/dist/index.d.ts +18 -24
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +15 -15
  29. package/dist/input/gamepad-mapping.d.ts +134 -0
  30. package/dist/input/gamepad-mapping.d.ts.map +1 -0
  31. package/dist/input/gamepad-mapping.js +146 -0
  32. package/dist/input/gamepad.d.ts +74 -0
  33. package/dist/input/gamepad.d.ts.map +1 -0
  34. package/dist/input/gamepad.js +288 -0
  35. package/dist/input/index.d.ts +6 -0
  36. package/dist/input/index.d.ts.map +1 -0
  37. package/dist/input/index.js +1 -0
  38. package/dist/input/input.d.ts +76 -0
  39. package/dist/input/input.d.ts.map +1 -0
  40. package/dist/input/input.js +164 -0
  41. package/dist/input/keyboard.d.ts +15 -0
  42. package/dist/input/keyboard.d.ts.map +1 -0
  43. package/dist/input/keyboard.js +53 -0
  44. package/dist/input/mouse.d.ts +108 -0
  45. package/dist/input/mouse.d.ts.map +1 -0
  46. package/dist/input/mouse.js +241 -0
  47. package/dist/like.d.ts +80 -0
  48. package/dist/like.d.ts.map +1 -0
  49. package/dist/like.js +5 -0
  50. package/dist/math/index.d.ts +18 -0
  51. package/dist/math/index.d.ts.map +1 -0
  52. package/dist/math/index.js +17 -0
  53. package/dist/math/rect.d.ts +68 -0
  54. package/dist/math/rect.d.ts.map +1 -0
  55. package/dist/{core → math}/rect.js +48 -66
  56. package/dist/math/vector2.d.ts +133 -0
  57. package/dist/math/vector2.d.ts.map +1 -0
  58. package/dist/math/vector2.js +111 -0
  59. package/dist/prefab-scenes/index.d.ts +8 -0
  60. package/dist/prefab-scenes/index.d.ts.map +1 -0
  61. package/dist/prefab-scenes/index.js +7 -0
  62. package/dist/prefab-scenes/mapGamepad.d.ts +28 -0
  63. package/dist/prefab-scenes/mapGamepad.d.ts.map +1 -0
  64. package/dist/prefab-scenes/mapGamepad.js +181 -0
  65. package/dist/prefab-scenes/startScreen.d.ts +59 -0
  66. package/dist/prefab-scenes/startScreen.d.ts.map +1 -0
  67. package/dist/{scenes/startup.js → prefab-scenes/startScreen.js} +48 -8
  68. package/dist/scene.d.ts +104 -6
  69. package/dist/scene.d.ts.map +1 -1
  70. package/dist/scene.js +28 -1
  71. package/dist/timer/index.d.ts +2 -0
  72. package/dist/timer/index.d.ts.map +1 -0
  73. package/dist/timer/timer.d.ts +32 -0
  74. package/dist/timer/timer.d.ts.map +1 -0
  75. package/dist/{core → timer}/timer.js +19 -14
  76. package/package.json +27 -2
  77. package/dist/core/audio.d.ts.map +0 -1
  78. package/dist/core/canvas-config.d.ts +0 -22
  79. package/dist/core/canvas-config.d.ts.map +0 -1
  80. package/dist/core/canvas-config.js +0 -14
  81. package/dist/core/canvas-manager.d.ts +0 -32
  82. package/dist/core/canvas-manager.d.ts.map +0 -1
  83. package/dist/core/canvas-manager.js +0 -179
  84. package/dist/core/events.d.ts +0 -31
  85. package/dist/core/events.d.ts.map +0 -1
  86. package/dist/core/gamepad-buttons.d.ts +0 -23
  87. package/dist/core/gamepad-buttons.d.ts.map +0 -1
  88. package/dist/core/gamepad-buttons.js +0 -36
  89. package/dist/core/gamepad-mapping.d.ts +0 -19
  90. package/dist/core/gamepad-mapping.d.ts.map +0 -1
  91. package/dist/core/gamepad-mapping.js +0 -223
  92. package/dist/core/gamepad.d.ts +0 -61
  93. package/dist/core/gamepad.d.ts.map +0 -1
  94. package/dist/core/gamepad.js +0 -237
  95. package/dist/core/graphics.d.ts +0 -93
  96. package/dist/core/graphics.d.ts.map +0 -1
  97. package/dist/core/graphics.js +0 -289
  98. package/dist/core/input-state.d.ts +0 -14
  99. package/dist/core/input-state.d.ts.map +0 -1
  100. package/dist/core/input-state.js +0 -50
  101. package/dist/core/input.d.ts +0 -33
  102. package/dist/core/input.d.ts.map +0 -1
  103. package/dist/core/input.js +0 -117
  104. package/dist/core/keyboard.d.ts +0 -16
  105. package/dist/core/keyboard.d.ts.map +0 -1
  106. package/dist/core/keyboard.js +0 -83
  107. package/dist/core/like.d.ts +0 -59
  108. package/dist/core/like.d.ts.map +0 -1
  109. package/dist/core/mouse.d.ts +0 -45
  110. package/dist/core/mouse.d.ts.map +0 -1
  111. package/dist/core/mouse.js +0 -182
  112. package/dist/core/rect.d.ts +0 -26
  113. package/dist/core/rect.d.ts.map +0 -1
  114. package/dist/core/timer.d.ts +0 -18
  115. package/dist/core/timer.d.ts.map +0 -1
  116. package/dist/core/vector2.d.ts +0 -26
  117. package/dist/core/vector2.d.ts.map +0 -1
  118. package/dist/core/vector2.js +0 -105
  119. package/dist/scenes/startup.d.ts +0 -18
  120. package/dist/scenes/startup.d.ts.map +0 -1
  121. /package/dist/{core/events.js → audio/index.js} +0 -0
  122. /package/dist/{core/like.js → timer/index.js} +0 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * @module GamepadMapping
3
+ *
4
+ * A database, generated on module load,
5
+ * which uses SDL's database to coerce
6
+ * browser APIs into physical gamepad button
7
+ * mappings.
8
+ *
9
+ * Browser API shortcomings:
10
+ * - No standard way of exposing vendor and product
11
+ * - Almost nothing is standard
12
+ * - Vendor and product alone doesn't suffice for GUID -- Different controllers have the same.
13
+ * - D-pads either get mapped to an axis (last pair of axes in Chromium) or buttons (Firefox).
14
+ * - Analog axes get mapped differently in Firefox and Chromium.
15
+ *
16
+ * How we overcome them:
17
+ * - We parse out vendor and product based on currently known formats.
18
+ * - We go with best-match and always fall back on manual mapping.
19
+ */
20
+ /**
21
+ * ref: https://www.w3.org/TR/gamepad/#dfn-standard-gamepad
22
+ * note: `num` is only the corresponding number on standard mapping above.
23
+ *
24
+ * The point of the mapping system is to apply that _or_ non-standard mappings,
25
+ * Which are exceedingly common.
26
+ */
27
+ const buttonMap = [
28
+ { sdl: "a", like: "BBottom", num: 0, name: "Bottom Face Button" },
29
+ { sdl: "b", like: "BRight", num: 1, name: "Right Face Button" },
30
+ { sdl: "x", like: "BLeft", num: 2, name: "Left Face Button" },
31
+ { sdl: "y", like: "BTop", num: 3, name: "Top Face Button" },
32
+ { sdl: "leftshoulder", like: "L1", num: 4, name: "Left shoulder (front)" },
33
+ { sdl: "rightshoulder", like: "R1", num: 5, name: "Right shoulder (front)" },
34
+ { sdl: "lefttrigger", like: "L2", num: 6, name: "Left shoulder (rear)" },
35
+ { sdl: "righttrigger", like: "R2", num: 7, name: "Right shoulder (rear)" },
36
+ { sdl: "back", like: "MenuLeft", num: 8, name: "Left Menu Button" },
37
+ { sdl: "start", like: "MenuRight", num: 9, name: "Right Menu Button" },
38
+ { sdl: "leftstick", like: "LeftStick", num: 10, name: "Left Stick Button" },
39
+ {
40
+ sdl: "rightstick",
41
+ like: "RightStick",
42
+ num: 11,
43
+ name: "Right Stick Button",
44
+ },
45
+ { sdl: "dpup", like: "Up", num: 12, name: "D-Pad Up" },
46
+ { sdl: "dpdown", like: "Down", num: 13, name: "D-Pad Down" },
47
+ { sdl: "dpleft", like: "Left", num: 14, name: "D-Pad Left" },
48
+ { sdl: "dpright", like: "Right", num: 15, name: "D-Pad right" },
49
+ ];
50
+ export const defaultMapping = (stickCount) => ({
51
+ buttons: {},
52
+ sticks: Array(stickCount / 2)
53
+ .fill(0)
54
+ .map((_, i) => [
55
+ { index: i * 2, invert: false },
56
+ { index: i * 2 + 1, invert: false },
57
+ ]),
58
+ });
59
+ export const standardButtonMapping = () => Object.fromEntries(buttonMap.map(({ like, num }) => [num, like]));
60
+ export const allButtons = new Set(buttonMap.map(({ like }) => like));
61
+ export const fullButtonName = new Map(buttonMap.map(({ like, name }) => [like, name]));
62
+ export const mapStick = (gp, mapping) => {
63
+ return mapping.map((axis) => (axis.invert ? -1 : 1) * (gp.axes[axis.index] ?? 0));
64
+ };
65
+ //// ************* SDL Gamepad auto-binding system ******************* ////
66
+ // @ts-ignore
67
+ import gamecontrollerdb from "../gamecontrollerdb.txt?raw";
68
+ const sdlButtonSet = new Set(buttonMap.map(({ sdl }) => sdl));
69
+ const sdlToLikeMap = new Map(buttonMap.map(({ sdl, like }) => [sdl, like]));
70
+ const mappingDb = generateMappingDb(gamecontrollerdb);
71
+ function generateMappingDb(db) {
72
+ const dbEntries = db
73
+ .split("\n")
74
+ .map((l) => l.trim())
75
+ .filter((line) => line !== "" && !line.startsWith("#"))
76
+ .map(parseDbLine);
77
+ console.log(`[Gamepad] Parsed ${dbEntries.length} entries from DB`);
78
+ const mappingDb = Object.fromEntries(dbEntries);
79
+ console.log(`[Gamepad] Final entry count: ${Object.keys(mappingDb).length}`);
80
+ return mappingDb;
81
+ }
82
+ function parseDbLine(line) {
83
+ const [guid, name, ...mappings] = line.split(",");
84
+ mappings.pop();
85
+ const vpNum = 0x1 * parseInt(guid.substring(16, 18), 16) +
86
+ 0x100 * parseInt(guid.substring(18, 20), 16) +
87
+ 0x10000 * parseInt(guid.substring(8, 10), 16) +
88
+ 0x1000000 * parseInt(guid.substring(10, 12), 16);
89
+ const mapping = Object.fromEntries(mappings
90
+ .map((s) => {
91
+ const [sdl, bname] = s.split(":");
92
+ const browserIndex = sdlRawButtonToBrowser(bname);
93
+ return (browserIndex !== undefined &&
94
+ sdlButtonSet.has(sdl) && [browserIndex, sdlToLikeMap.get(sdl)]);
95
+ })
96
+ .filter((v) => !!v));
97
+ return [vpNum, { name, mapping }];
98
+ }
99
+ function sdlRawButtonToBrowser(btn) {
100
+ return btn.startsWith("b")
101
+ ? Number(btn.substring(1))
102
+ : btn.startsWith("h")
103
+ ? { 1: 12, 2: 13, 4: 14, 8: 15 }[Number(btn.substring(3))]
104
+ : undefined;
105
+ }
106
+ export function getSdlMapping(gamepad) {
107
+ const parsed = tryParseId(gamepad.id);
108
+ if (parsed) {
109
+ const [vendorStr, productStr, nameStr] = parsed;
110
+ const vendor = parseInt(vendorStr, 16);
111
+ const product = parseInt(productStr, 16);
112
+ const name = nameStr.trim();
113
+ const mapping = mappingDb[vendor * 0x10000 + product];
114
+ if (mapping) {
115
+ console.log(`[Gamepad] Found SDL db mapping for '${name}'`);
116
+ return {
117
+ vendor,
118
+ product,
119
+ name,
120
+ sdlName: mapping.name,
121
+ mapping: mapping.mapping,
122
+ };
123
+ }
124
+ else {
125
+ console.log(`[Gamepad] No SDL db mapping found for '${gamepad.id}.`);
126
+ }
127
+ }
128
+ else {
129
+ console.log(`[Gamepad] Failed to parse id: ${gamepad.id}. Please report this bug with the name of your web browser.`);
130
+ }
131
+ }
132
+ function tryParseId(id) {
133
+ const infoC = id.match(/^([^(]+)\(Vendor: ([0-9a-f]+) Product: ([0-9a-f]+)/i);
134
+ if (infoC) {
135
+ // chrome pattern: Name(Vendor: VEND Product: PROD)
136
+ const [, name, vendor, product] = infoC;
137
+ return [vendor, product, name.trim()];
138
+ }
139
+ else {
140
+ // firefox pattern: VEND-PROD-Name
141
+ const infoF = id.split("-");
142
+ if (infoF.length == 3) {
143
+ return infoF;
144
+ }
145
+ }
146
+ }
@@ -0,0 +1,74 @@
1
+ import { GamepadMapping, LikeButton } from './gamepad-mapping';
2
+ import { type LikeGamepadEvent } from '../events';
3
+ import { Vector2 } from '../math/vector2';
4
+ import { EngineProps } from '../engine';
5
+ /** A selector for a gamepad. */
6
+ export type GamepadTarget = number | "any";
7
+ /** LIKE Gamepad Wrapper
8
+ *
9
+ * - Allows events/callbacks to be sent from joy buttons.
10
+ * - Can track if any gamepad has a button pressed / just pressed.
11
+ * - Remaps raw input numbers to readable strings -- by default using SDL database.
12
+ *
13
+ * If you're planning on supporting gamepads, please include a
14
+ * way to generate {@link GamepadMapping} and set it with {@link Gamepad.setMapping}.
15
+ *
16
+ * If you don't want to make your own, take a look at `prefab-scenes/mapGamepad`.
17
+ */
18
+ export declare class Gamepad {
19
+ private dispatch;
20
+ private gamepads;
21
+ private autoLoadMapping;
22
+ constructor(props: EngineProps<LikeGamepadEvent>);
23
+ private onGamepadConnected;
24
+ /**
25
+ * @private
26
+ * Called by the engine every frame.
27
+ */
28
+ update(): void;
29
+ /**
30
+ *
31
+ * @param target Which controller?
32
+ * @returns all of the sticks. Convention is 0 = left, 1 = right.
33
+ */
34
+ getSticks(target: number): Vector2[];
35
+ fullButtonName(name: LikeButton): string;
36
+ private checkButton;
37
+ /** Check if a gamepad button is down. */
38
+ isDown(target: GamepadTarget, button: LikeButton | number): boolean | undefined;
39
+ /**
40
+ * Returns true for only one frame/update if a button is pressed.
41
+ * Considered an alternative to `like.gamepadpressed`.
42
+ */
43
+ justPressed(target: GamepadTarget, button: LikeButton | number): boolean | undefined;
44
+ /**
45
+ * Get a controller mapping.
46
+ * Note that modifying this mapping in place will modify the target controller.
47
+ * However, use `setMapping` to finalize the mapping.
48
+ */
49
+ getMapping(index: number): GamepadMapping | undefined;
50
+ /**
51
+ * Set the mapping for a particular controller.
52
+ *
53
+ * Set `save = false` if you don't want this written into localstorage.
54
+ */
55
+ setMapping(index: number, mapping: GamepadMapping, save?: boolean): void;
56
+ /**
57
+ * Get saved mapping from db, if it exists.
58
+ */
59
+ loadMapping(index: number): GamepadMapping | undefined;
60
+ /**
61
+ * Save a mapping to persistant storage
62
+ */
63
+ saveMapping(index: number, mapping: GamepadMapping): void;
64
+ /**
65
+ * Enable automatically loading mappings.
66
+ *
67
+ * When a gamepad with a known (to this system) ID is plugged in,
68
+ * this will load the previously saved mapping.
69
+ *
70
+ * @param enable
71
+ */
72
+ enableAutoLoadMapping(enable: boolean): void;
73
+ }
74
+ //# sourceMappingURL=gamepad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad.d.ts","sourceRoot":"","sources":["../../src/input/gamepad.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,cAAc,EAAiB,UAAU,EAAY,MAAM,mBAAmB,CAAC;AACxH,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,gCAAgC;AAChC,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,KAAK,CAAC;AAE3C;;;;;;;;;;GAUG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,eAAe,CAAQ;gBAEnB,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC;IAgChD,OAAO,CAAC,kBAAkB;IA+B1B;;;OAGG;IACH,MAAM,IAAI,IAAI;IAId;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE;IAQpC,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAIxC,OAAO,CAAC,WAAW;IAYnB,yCAAyC;IACzC,MAAM,CACJ,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,UAAU,GAAG,MAAM,GAC1B,OAAO,GAAG,SAAS;IAItB;;;OAGG;IACH,WAAW,CACT,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,UAAU,GAAG,MAAM,GAC1B,OAAO,GAAG,SAAS;IAItB;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIrD;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,UAAO;IAU9D;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAYtD;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;IASlD;;;;;;;OAOG;IACH,qBAAqB,CAAC,MAAM,EAAE,OAAO;CAGtC"}
@@ -0,0 +1,288 @@
1
+ import { defaultMapping, fullButtonName, getSdlMapping, mapStick } from './gamepad-mapping';
2
+ /** LIKE Gamepad Wrapper
3
+ *
4
+ * - Allows events/callbacks to be sent from joy buttons.
5
+ * - Can track if any gamepad has a button pressed / just pressed.
6
+ * - Remaps raw input numbers to readable strings -- by default using SDL database.
7
+ *
8
+ * If you're planning on supporting gamepads, please include a
9
+ * way to generate {@link GamepadMapping} and set it with {@link Gamepad.setMapping}.
10
+ *
11
+ * If you don't want to make your own, take a look at `prefab-scenes/mapGamepad`.
12
+ */
13
+ export class Gamepad {
14
+ constructor(props) {
15
+ Object.defineProperty(this, "dispatch", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: void 0
20
+ });
21
+ Object.defineProperty(this, "gamepads", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: {}
26
+ });
27
+ Object.defineProperty(this, "autoLoadMapping", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: true
32
+ });
33
+ this.dispatch = props.dispatch;
34
+ const { abort } = props;
35
+ // Register event listeners
36
+ window.addEventListener("gamepadconnected", this.onGamepadConnected.bind(this), {
37
+ signal: abort,
38
+ });
39
+ window.addEventListener("gamepaddisconnected", (ev) => {
40
+ console.log(`[Gamepad] Disconnected ${ev.gamepad.id}`);
41
+ delete this.gamepads[ev.gamepad.index];
42
+ this.dispatch("gamepaddisconnected", [ev.gamepad.index]);
43
+ }, { signal: abort });
44
+ window.addEventListener("blur", () => {
45
+ for (const gps of Object.values(this.gamepads)) {
46
+ gps.clear();
47
+ }
48
+ }, { signal: abort });
49
+ }
50
+ onGamepadConnected(ev) {
51
+ const gps = new GamepadState(ev.gamepad.index);
52
+ this.gamepads[ev.gamepad.index] = gps;
53
+ console.log(`[Gamepad] Connected ${ev.gamepad.id}. buttons: ${ev.gamepad.buttons.length}, axes: ${ev.gamepad.axes.length}`);
54
+ const mapping = this.loadMapping(ev.gamepad.index);
55
+ if (this.autoLoadMapping && mapping) {
56
+ gps.mapping = mapping;
57
+ console.log(`[Gamepad] Applied presaved mapping.`);
58
+ }
59
+ else if (ev.gamepad.mapping == 'standard') {
60
+ gps.mapping = defaultMapping(ev.gamepad.axes.length / 2);
61
+ console.log(`Loaded standard mapping.`);
62
+ }
63
+ else {
64
+ const sdlMapping = getSdlMapping(ev.gamepad);
65
+ if (sdlMapping) {
66
+ gps.mapping.buttons = sdlMapping.mapping;
67
+ console.log(`[Gamepad] Connected, applied SDL database mapping.`);
68
+ }
69
+ else {
70
+ console.log(`[Gamepad] Could not find mapping for gamepad. Consider remapping it.`);
71
+ }
72
+ }
73
+ this.dispatch("gamepadconnected", [ev.gamepad.index]);
74
+ }
75
+ /**
76
+ * @private
77
+ * Called by the engine every frame.
78
+ */
79
+ update() {
80
+ Object.values(this.gamepads).forEach((gp) => gp.update(this.dispatch));
81
+ }
82
+ /**
83
+ *
84
+ * @param target Which controller?
85
+ * @returns all of the sticks. Convention is 0 = left, 1 = right.
86
+ */
87
+ getSticks(target) {
88
+ const gp = this.gamepads[target];
89
+ if (gp) {
90
+ return gp.getSticks();
91
+ }
92
+ return [];
93
+ }
94
+ fullButtonName(name) {
95
+ return fullButtonName.get(name) ?? name;
96
+ }
97
+ checkButton(target, button, mode) {
98
+ if (target == "any") {
99
+ return Object.values(this.gamepads).some((gp) => gp[mode](button));
100
+ }
101
+ else {
102
+ return this.gamepads[target]?.[mode](button);
103
+ }
104
+ }
105
+ /** Check if a gamepad button is down. */
106
+ isDown(target, button) {
107
+ return this.checkButton(target, button, "isDown");
108
+ }
109
+ /**
110
+ * Returns true for only one frame/update if a button is pressed.
111
+ * Considered an alternative to `like.gamepadpressed`.
112
+ */
113
+ justPressed(target, button) {
114
+ return this.checkButton(target, button, "justPressed");
115
+ }
116
+ /**
117
+ * Get a controller mapping.
118
+ * Note that modifying this mapping in place will modify the target controller.
119
+ * However, use `setMapping` to finalize the mapping.
120
+ */
121
+ getMapping(index) {
122
+ return this.gamepads[index]?.mapping;
123
+ }
124
+ /**
125
+ * Set the mapping for a particular controller.
126
+ *
127
+ * Set `save = false` if you don't want this written into localstorage.
128
+ */
129
+ setMapping(index, mapping, save = true) {
130
+ const gp = this.gamepads[index];
131
+ if (gp) {
132
+ gp.mapping = mapping;
133
+ if (save) {
134
+ this.saveMapping(index, mapping);
135
+ }
136
+ }
137
+ }
138
+ /**
139
+ * Get saved mapping from db, if it exists.
140
+ */
141
+ loadMapping(index) {
142
+ const gp = navigator.getGamepads()?.[index];
143
+ if (gp) {
144
+ const path = getLocalstoragePath(gp);
145
+ console.log(`[Gamepad] Found saved mapping for ${gp.id}.`);
146
+ const item = localStorage.getItem(path);
147
+ if (item) {
148
+ return JSON.parse(item);
149
+ }
150
+ }
151
+ }
152
+ /**
153
+ * Save a mapping to persistant storage
154
+ */
155
+ saveMapping(index, mapping) {
156
+ const gp = navigator.getGamepads()?.[index];
157
+ if (gp) {
158
+ const path = getLocalstoragePath(gp);
159
+ console.log(`[Gamepad] Saved mapping ${path} to localStorage.`);
160
+ localStorage.setItem(path, JSON.stringify(mapping));
161
+ }
162
+ }
163
+ /**
164
+ * Enable automatically loading mappings.
165
+ *
166
+ * When a gamepad with a known (to this system) ID is plugged in,
167
+ * this will load the previously saved mapping.
168
+ *
169
+ * @param enable
170
+ */
171
+ enableAutoLoadMapping(enable) {
172
+ this.autoLoadMapping = enable;
173
+ }
174
+ }
175
+ function getLocalstoragePath(gamepad) {
176
+ return `${gamepad.axes.length}A${gamepad.buttons.length}B${gamepad.id}`;
177
+ }
178
+ const maxButtons = 64;
179
+ /** Internal class: Using it externally could result
180
+ * in a gamepad being disconnected and still trying to maintain
181
+ * its state.
182
+ */
183
+ class GamepadState {
184
+ constructor(index) {
185
+ Object.defineProperty(this, "index", {
186
+ enumerable: true,
187
+ configurable: true,
188
+ writable: true,
189
+ value: index
190
+ });
191
+ Object.defineProperty(this, "mapping", {
192
+ enumerable: true,
193
+ configurable: true,
194
+ writable: true,
195
+ value: void 0
196
+ });
197
+ Object.defineProperty(this, "downNums", {
198
+ enumerable: true,
199
+ configurable: true,
200
+ writable: true,
201
+ value: []
202
+ });
203
+ Object.defineProperty(this, "lastDownNums", {
204
+ enumerable: true,
205
+ configurable: true,
206
+ writable: true,
207
+ value: []
208
+ });
209
+ Object.defineProperty(this, "down", {
210
+ enumerable: true,
211
+ configurable: true,
212
+ writable: true,
213
+ value: {}
214
+ });
215
+ Object.defineProperty(this, "lastDown", {
216
+ enumerable: true,
217
+ configurable: true,
218
+ writable: true,
219
+ value: {}
220
+ });
221
+ const gp = navigator.getGamepads()[this.index];
222
+ this.mapping = defaultMapping(gp.axes.length);
223
+ }
224
+ isDown(button) {
225
+ return typeof (button) == "number" ? !!this.downNums[button] : !!this.down[button];
226
+ }
227
+ justPressed(button) {
228
+ return typeof (button) == "number" ?
229
+ (!!this.downNums[button] && !this.lastDownNums[button]) :
230
+ (!!this.down[button] && !this.lastDown[button]);
231
+ }
232
+ map(button) {
233
+ return (this.mapping.buttons[button] ??
234
+ (button < maxButtons
235
+ ? `Button${button}`
236
+ : `Axis${Math.floor((button - maxButtons) / 2)}${button % 2 ? "-" : "+"}`));
237
+ }
238
+ update(dispatch) {
239
+ const gp = navigator.getGamepads()[this.index];
240
+ if (!gp)
241
+ return;
242
+ [this.downNums, this.lastDownNums] = [this.lastDownNums, this.downNums];
243
+ for (const k in this.downNums) {
244
+ delete this.downNums[Number(k)];
245
+ }
246
+ gp.buttons.forEach((btn, i) => {
247
+ if (btn.pressed) {
248
+ this.downNums[i] = true;
249
+ }
250
+ });
251
+ gp.axes.forEach((axis, i) => {
252
+ const pos = Math.round(axis);
253
+ if (pos == 0)
254
+ return;
255
+ const index = 64 + i * 2 + (pos == -1 ? 1 : 0);
256
+ this.downNums[index] = true;
257
+ });
258
+ [this.down, this.lastDown] = [this.lastDown, this.down];
259
+ for (const k in this.down) {
260
+ delete this.down[k];
261
+ }
262
+ for (const i in this.downNums) {
263
+ const name = this.map(Number(i));
264
+ this.down[name] = true;
265
+ if (!this.lastDownNums[Number(i)]) {
266
+ dispatch("gamepadpressed", [this.index, name, Number(i)]);
267
+ }
268
+ }
269
+ for (const i in this.lastDownNums) {
270
+ if (!this.downNums[Number(i)]) {
271
+ const name = this.map(Number(i));
272
+ dispatch("gamepadreleased", [this.index, name, Number(i)]);
273
+ }
274
+ }
275
+ }
276
+ getSticks() {
277
+ const gp = navigator.getGamepads()[this.index];
278
+ return this.mapping.sticks.map((stick) => mapStick(gp, stick));
279
+ }
280
+ clear() {
281
+ for (const k in this.lastDown) {
282
+ delete this.lastDown[k];
283
+ }
284
+ for (const k in this.down) {
285
+ delete this.down[k];
286
+ }
287
+ }
288
+ }
@@ -0,0 +1,6 @@
1
+ export type { Input, InputType, InputBinding, } from "./input";
2
+ export type { GamepadTarget, Gamepad, } from "./gamepad";
3
+ export type { LikeButton, GamepadMapping, StickMapping, StickAxisMapping, } from "./gamepad-mapping";
4
+ export { defaultMapping, allButtons } from "./gamepad-mapping";
5
+ export type { MouseSetMode, Mouse, } from "./mouse";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/input/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,KAAK,EACL,SAAS,EACT,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,aAAa,EACb,OAAO,GACR,MAAM,WAAW,CAAA;AAElB,YAAY,EACV,UAAU,EACV,cAAc,EACd,YAAY,EACZ,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/D,YAAY,EACV,YAAY,EACZ,KAAK,GACN,MAAM,SAAS,CAAC"}
@@ -0,0 +1 @@
1
+ export { defaultMapping, allButtons } from "./gamepad-mapping";
@@ -0,0 +1,76 @@
1
+ import type { Keyboard } from './keyboard';
2
+ import type { Mouse } from './mouse';
3
+ import { Gamepad, GamepadTarget } from './gamepad';
4
+ import { LikeButton } from './gamepad-mapping';
5
+ import { MouseButton, Dispatcher } from '../events';
6
+ export type InputType = InputBinding['type'];
7
+ export type InputBinding = {
8
+ type: 'keyboard';
9
+ scancode: string;
10
+ } | {
11
+ type: 'mouse';
12
+ button: MouseButton;
13
+ } | {
14
+ type: 'gamepad';
15
+ gamepad: GamepadTarget;
16
+ button: LikeButton;
17
+ };
18
+ export declare class Input {
19
+ private dispatch;
20
+ private currState;
21
+ private prevState;
22
+ private actionTable;
23
+ private keyboard;
24
+ private mouse;
25
+ private gamepad;
26
+ constructor(dispatch: Dispatcher<'actionpressed' | 'actionreleased'>, deps: {
27
+ keyboard: Keyboard;
28
+ mouse: Mouse;
29
+ gamepad: Gamepad;
30
+ });
31
+ /**
32
+ * This is the easiest way to set-and-forget input => action mapping.
33
+ *
34
+ * Or, it's a helper to remove actions -- `setAction(action)`
35
+ * will simply clear the action away.
36
+ *
37
+ * For input strings:
38
+ * - Mouse is `MouseLeft`, `MouseRight`, or `MouseMiddle`.
39
+ * - Joypad is 'Left', 'L1', or any joypad button. {@link LikeButton}
40
+ * - Keyboard is the name of scancodes, which are based on key positions. Choose from a subset of portable, web-safe scancodes:
41
+ * - Alphabetical: `KeyA`, `KeyB`, ...
42
+ * - Numeric: `Digit0`, `Digit1`, ...
43
+ * - `ArrowLeft`, `ArrowRight`, `ArrowUp`, `ArrowDown`
44
+ * - `ShiftLeft`, `ShiftRight`
45
+ * - `Minus`
46
+ * - `Equal` (also has a plus sign)
47
+ * - `BracketLeft` and `BracketRight`
48
+ * - `Semicolon`
49
+ * - `Quote`
50
+ * - `Backquote` (also has tilde)
51
+ * - `Backslash`
52
+ * - `Comma`
53
+ * - `Period`
54
+ * - `Slash`
55
+ * - `Backspace`
56
+ * - `Enter`
57
+ *
58
+ * @param action
59
+ * @param inputs
60
+ */
61
+ setAction(action: string, inputs?: (string | InputBinding)[]): void;
62
+ /**
63
+ * Map a single input onto an action.
64
+ */
65
+ appendToAction(action: string, input: InputBinding | string): void;
66
+ /**
67
+ * Get the mapping entry for a specific action.
68
+ */
69
+ getActionMapping(action: string): InputBinding[];
70
+ isDown(action: string): boolean;
71
+ justPressed(action: string): boolean;
72
+ justReleased(action: string): boolean;
73
+ update(): void;
74
+ private isBindingActive;
75
+ }
76
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/input/input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAc,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AAC7C,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAEpE,qBAAa,KAAK;IASd,OAAO,CAAC,QAAQ;IARlB,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,OAAO,CAAU;gBAGf,QAAQ,EAAE,UAAU,CAAC,eAAe,GAAG,gBAAgB,CAAC,EAChE,IAAI,EAAE;QACJ,QAAQ,EAAE,QAAQ,CAAC;QACnB,KAAK,EAAE,KAAK,CAAC;QACb,OAAO,EAAE,OAAO,CAAC;KAClB;IAOH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,CAAC,MAAM,GAAG,YAAY,CAAC,EAAO,GAAG,IAAI;IAUvE;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM;IAM3D;;OAEG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;IAIhD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAM/B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIpC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIrC,MAAM;IAiBN,OAAO,CAAC,eAAe;CAaxB"}