like2d 2.9.0 → 2.10.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.
- package/README.md +21 -17
- package/dist/__benchmarks__/vector2.bench.d.ts +2 -0
- package/dist/__benchmarks__/vector2.bench.d.ts.map +1 -0
- package/dist/__benchmarks__/vector2.bench.js +74 -0
- package/dist/{core → audio}/audio.d.ts +12 -3
- package/dist/audio/audio.d.ts.map +1 -0
- package/dist/{core → audio}/audio.js +10 -2
- package/dist/audio/index.d.ts +2 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +1 -0
- package/dist/engine.d.ts +12 -42
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +34 -76
- package/dist/{core/events.d.ts → events.d.ts} +27 -50
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +5 -0
- package/dist/{core → graphics}/canvas.d.ts +18 -11
- package/dist/graphics/canvas.d.ts.map +1 -0
- package/dist/{core → graphics}/canvas.js +73 -58
- package/dist/{core/graphics.d.ts → graphics/drawing.d.ts} +25 -25
- package/dist/graphics/drawing.d.ts.map +1 -0
- package/dist/{core/graphics.js → graphics/drawing.js} +59 -52
- package/dist/graphics/index.d.ts +19 -0
- package/dist/graphics/index.d.ts.map +1 -0
- package/dist/graphics/index.js +13 -0
- package/dist/index.d.ts +3 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -21
- package/dist/input/controllerdb.json +1 -0
- package/dist/input/gamepad-mapping.d.ts +119 -0
- package/dist/input/gamepad-mapping.d.ts.map +1 -0
- package/dist/input/gamepad-mapping.js +114 -0
- package/dist/input/gamepad.d.ts +73 -0
- package/dist/input/gamepad.d.ts.map +1 -0
- package/dist/input/gamepad.js +291 -0
- package/dist/input/index.d.ts +6 -0
- package/dist/input/index.d.ts.map +1 -0
- package/dist/input/index.js +1 -0
- package/dist/input/input.d.ts +76 -0
- package/dist/input/input.d.ts.map +1 -0
- package/dist/input/input.js +163 -0
- package/dist/input/keyboard.d.ts +15 -0
- package/dist/input/keyboard.d.ts.map +1 -0
- package/dist/{core → input}/keyboard.js +11 -21
- package/dist/input/mouse.d.ts +108 -0
- package/dist/input/mouse.d.ts.map +1 -0
- package/dist/input/mouse.js +241 -0
- package/dist/like.d.ts +80 -0
- package/dist/like.d.ts.map +1 -0
- package/dist/like.js +5 -0
- package/dist/math/index.d.ts +16 -0
- package/dist/math/index.d.ts.map +1 -1
- package/dist/math/index.js +16 -0
- package/dist/math/rect.d.ts +24 -27
- package/dist/math/rect.d.ts.map +1 -1
- package/dist/math/rect.js +47 -73
- package/dist/math/vector2.d.ts +87 -32
- package/dist/math/vector2.d.ts.map +1 -1
- package/dist/math/vector2.js +92 -110
- package/dist/prefab-scenes/index.d.ts +1 -0
- package/dist/prefab-scenes/index.d.ts.map +1 -1
- package/dist/prefab-scenes/index.js +1 -0
- package/dist/prefab-scenes/mapGamepad.d.ts +30 -0
- package/dist/prefab-scenes/mapGamepad.d.ts.map +1 -0
- package/dist/prefab-scenes/mapGamepad.js +192 -0
- package/dist/prefab-scenes/startScreen.d.ts +2 -2
- package/dist/prefab-scenes/startScreen.js +2 -2
- package/dist/scene.d.ts +2 -2
- package/dist/scene.d.ts.map +1 -1
- package/dist/timer/index.d.ts +2 -0
- package/dist/timer/index.d.ts.map +1 -0
- package/dist/timer/index.js +1 -0
- package/dist/timer/timer.d.ts +32 -0
- package/dist/timer/timer.d.ts.map +1 -0
- package/dist/{core → timer}/timer.js +20 -3
- package/package.json +21 -12
- package/dist/core/audio.d.ts.map +0 -1
- package/dist/core/canvas.d.ts.map +0 -1
- package/dist/core/events.d.ts.map +0 -1
- package/dist/core/events.js +0 -21
- package/dist/core/gamepad-mapping.d.ts +0 -58
- package/dist/core/gamepad-mapping.d.ts.map +0 -1
- package/dist/core/gamepad-mapping.js +0 -23
- package/dist/core/gamepad.d.ts +0 -37
- package/dist/core/gamepad.d.ts.map +0 -1
- package/dist/core/gamepad.js +0 -103
- package/dist/core/graphics.d.ts.map +0 -1
- package/dist/core/input-state.d.ts +0 -14
- package/dist/core/input-state.d.ts.map +0 -1
- package/dist/core/input-state.js +0 -50
- package/dist/core/input.d.ts +0 -40
- package/dist/core/input.d.ts.map +0 -1
- package/dist/core/input.js +0 -105
- package/dist/core/keyboard.d.ts +0 -15
- package/dist/core/keyboard.d.ts.map +0 -1
- package/dist/core/like.d.ts +0 -113
- package/dist/core/like.d.ts.map +0 -1
- package/dist/core/like.js +0 -9
- package/dist/core/mouse.d.ts +0 -52
- package/dist/core/mouse.d.ts.map +0 -1
- package/dist/core/mouse.js +0 -142
- package/dist/core/timer.d.ts +0 -15
- package/dist/core/timer.d.ts.map +0 -1
|
@@ -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;IAgBN,OAAO,CAAC,eAAe;CAaxB"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { allButtons } from './gamepad-mapping';
|
|
2
|
+
export class Input {
|
|
3
|
+
constructor(dispatch, deps) {
|
|
4
|
+
Object.defineProperty(this, "dispatch", {
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true,
|
|
8
|
+
value: dispatch
|
|
9
|
+
});
|
|
10
|
+
Object.defineProperty(this, "currState", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true,
|
|
14
|
+
value: new Set()
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(this, "prevState", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: new Set()
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(this, "actionTable", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: {}
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(this, "keyboard", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
configurable: true,
|
|
31
|
+
writable: true,
|
|
32
|
+
value: void 0
|
|
33
|
+
});
|
|
34
|
+
Object.defineProperty(this, "mouse", {
|
|
35
|
+
enumerable: true,
|
|
36
|
+
configurable: true,
|
|
37
|
+
writable: true,
|
|
38
|
+
value: void 0
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(this, "gamepad", {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
configurable: true,
|
|
43
|
+
writable: true,
|
|
44
|
+
value: void 0
|
|
45
|
+
});
|
|
46
|
+
this.keyboard = deps.keyboard;
|
|
47
|
+
this.mouse = deps.mouse;
|
|
48
|
+
this.gamepad = deps.gamepad;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* This is the easiest way to set-and-forget input => action mapping.
|
|
52
|
+
*
|
|
53
|
+
* Or, it's a helper to remove actions -- `setAction(action)`
|
|
54
|
+
* will simply clear the action away.
|
|
55
|
+
*
|
|
56
|
+
* For input strings:
|
|
57
|
+
* - Mouse is `MouseLeft`, `MouseRight`, or `MouseMiddle`.
|
|
58
|
+
* - Joypad is 'Left', 'L1', or any joypad button. {@link LikeButton}
|
|
59
|
+
* - Keyboard is the name of scancodes, which are based on key positions. Choose from a subset of portable, web-safe scancodes:
|
|
60
|
+
* - Alphabetical: `KeyA`, `KeyB`, ...
|
|
61
|
+
* - Numeric: `Digit0`, `Digit1`, ...
|
|
62
|
+
* - `ArrowLeft`, `ArrowRight`, `ArrowUp`, `ArrowDown`
|
|
63
|
+
* - `ShiftLeft`, `ShiftRight`
|
|
64
|
+
* - `Minus`
|
|
65
|
+
* - `Equal` (also has a plus sign)
|
|
66
|
+
* - `BracketLeft` and `BracketRight`
|
|
67
|
+
* - `Semicolon`
|
|
68
|
+
* - `Quote`
|
|
69
|
+
* - `Backquote` (also has tilde)
|
|
70
|
+
* - `Backslash`
|
|
71
|
+
* - `Comma`
|
|
72
|
+
* - `Period`
|
|
73
|
+
* - `Slash`
|
|
74
|
+
* - `Backspace`
|
|
75
|
+
* - `Enter`
|
|
76
|
+
*
|
|
77
|
+
* @param action
|
|
78
|
+
* @param inputs
|
|
79
|
+
*/
|
|
80
|
+
setAction(action, inputs = []) {
|
|
81
|
+
if (inputs.length) {
|
|
82
|
+
this.actionTable[action] = inputs.map(parseInput);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
delete this.actionTable[action];
|
|
86
|
+
this.currState.delete(action);
|
|
87
|
+
this.prevState.delete(action);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Map a single input onto an action.
|
|
92
|
+
*/
|
|
93
|
+
appendToAction(action, input) {
|
|
94
|
+
const am = this.actionTable[action] ?? [];
|
|
95
|
+
am.push(parseInput(input));
|
|
96
|
+
this.actionTable[action] = am;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get the mapping entry for a specific action.
|
|
100
|
+
*/
|
|
101
|
+
getActionMapping(action) {
|
|
102
|
+
return this.actionTable[action] ?? [];
|
|
103
|
+
}
|
|
104
|
+
isDown(action) {
|
|
105
|
+
const bindings = this.actionTable[action];
|
|
106
|
+
if (!bindings)
|
|
107
|
+
return false;
|
|
108
|
+
return bindings.some((binding) => this.isBindingActive(binding));
|
|
109
|
+
}
|
|
110
|
+
justPressed(action) {
|
|
111
|
+
return this.currState.has(action) && !this.prevState.has(action);
|
|
112
|
+
}
|
|
113
|
+
justReleased(action) {
|
|
114
|
+
return !this.currState.has(action) && this.prevState.has(action);
|
|
115
|
+
}
|
|
116
|
+
update() {
|
|
117
|
+
[this.prevState, this.currState] = [this.currState, this.prevState];
|
|
118
|
+
this.currState.clear();
|
|
119
|
+
for (const action of Object.keys(this.actionTable)) {
|
|
120
|
+
if (this.isDown(action)) {
|
|
121
|
+
if (!this.prevState.has(action)) {
|
|
122
|
+
this.dispatch('actionpressed', [action]);
|
|
123
|
+
}
|
|
124
|
+
this.currState.add(action);
|
|
125
|
+
}
|
|
126
|
+
else if (this.prevState.has(action)) {
|
|
127
|
+
this.dispatch('actionreleased', [action]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
isBindingActive(binding) {
|
|
132
|
+
switch (binding.type) {
|
|
133
|
+
case "keyboard":
|
|
134
|
+
return this.keyboard.isDown(binding.scancode);
|
|
135
|
+
case "mouse":
|
|
136
|
+
return this.mouse.isDown(binding.button);
|
|
137
|
+
case "gamepad": {
|
|
138
|
+
return !!this.gamepad.isDown(binding.gamepad, binding.button);
|
|
139
|
+
}
|
|
140
|
+
default:
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function parseInput(input) {
|
|
146
|
+
if (typeof input !== "string")
|
|
147
|
+
return input;
|
|
148
|
+
const normalized = input.trim();
|
|
149
|
+
if (normalized.startsWith("Mouse")) {
|
|
150
|
+
const buttonCode = normalized.replace("Mouse", "").toLowerCase();
|
|
151
|
+
return { type: "mouse", button: buttonCode };
|
|
152
|
+
}
|
|
153
|
+
if (allButtons.has(input) ||
|
|
154
|
+
normalized.startsWith("Button") ||
|
|
155
|
+
normalized.startsWith("Axis")) {
|
|
156
|
+
return {
|
|
157
|
+
type: "gamepad",
|
|
158
|
+
gamepad: "any",
|
|
159
|
+
button: normalized,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return { type: "keyboard", scancode: normalized };
|
|
163
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EngineProps } from "../engine";
|
|
2
|
+
type KEvent = 'keypressed' | 'keyreleased';
|
|
3
|
+
export declare class Keyboard {
|
|
4
|
+
private pressedScancodes;
|
|
5
|
+
private canvas;
|
|
6
|
+
private dispatch;
|
|
7
|
+
constructor(props: EngineProps<KEvent>);
|
|
8
|
+
private handleKeyDown;
|
|
9
|
+
private handleKeyUp;
|
|
10
|
+
private handleBlur;
|
|
11
|
+
isDown(scancode: string): boolean;
|
|
12
|
+
isAnyDown(...scancodes: string[]): boolean;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=keyboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/input/keyboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,KAAK,MAAM,GAAG,YAAY,GAAG,aAAa,CAAC;AAE3C,qBAAa,QAAQ;IACnB,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAqB;gBAEzB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;IAUtC,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,UAAU;IAIlB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIjC,SAAS,CAAC,GAAG,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO;CAG3C"}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
export class
|
|
2
|
-
constructor(
|
|
3
|
-
Object.defineProperty(this, "dispatch", {
|
|
4
|
-
enumerable: true,
|
|
5
|
-
configurable: true,
|
|
6
|
-
writable: true,
|
|
7
|
-
value: dispatch
|
|
8
|
-
});
|
|
1
|
+
export class Keyboard {
|
|
2
|
+
constructor(props) {
|
|
9
3
|
Object.defineProperty(this, "pressedScancodes", {
|
|
10
4
|
enumerable: true,
|
|
11
5
|
configurable: true,
|
|
@@ -16,20 +10,20 @@ export class KeyboardInternal {
|
|
|
16
10
|
enumerable: true,
|
|
17
11
|
configurable: true,
|
|
18
12
|
writable: true,
|
|
19
|
-
value:
|
|
13
|
+
value: void 0
|
|
20
14
|
});
|
|
21
|
-
Object.defineProperty(this, "
|
|
15
|
+
Object.defineProperty(this, "dispatch", {
|
|
22
16
|
enumerable: true,
|
|
23
17
|
configurable: true,
|
|
24
18
|
writable: true,
|
|
25
|
-
value:
|
|
19
|
+
value: void 0
|
|
26
20
|
});
|
|
27
|
-
this.canvas = canvas;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
21
|
+
this.canvas = props.canvas;
|
|
22
|
+
this.dispatch = props.dispatch;
|
|
23
|
+
const { abort } = props;
|
|
24
|
+
this.canvas.addEventListener('keydown', this.handleKeyDown.bind(this), { signal: abort });
|
|
25
|
+
this.canvas.addEventListener('keyup', this.handleKeyUp.bind(this), { signal: abort });
|
|
26
|
+
this.canvas.addEventListener('blur', this.handleBlur.bind(this), { signal: abort });
|
|
33
27
|
}
|
|
34
28
|
handleKeyDown(e) {
|
|
35
29
|
const scrollKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space', 'PageUp', 'PageDown', 'Home', 'End'];
|
|
@@ -50,10 +44,6 @@ export class KeyboardInternal {
|
|
|
50
44
|
handleBlur() {
|
|
51
45
|
this.pressedScancodes.clear();
|
|
52
46
|
}
|
|
53
|
-
_dispose() {
|
|
54
|
-
this.abort.abort();
|
|
55
|
-
this.pressedScancodes.clear();
|
|
56
|
-
}
|
|
57
47
|
isDown(scancode) {
|
|
58
48
|
return this.pressedScancodes.has(scancode);
|
|
59
49
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { type Vector2 } from '../math/vector2';
|
|
2
|
+
import { type MouseButton, type LikeMouseEvent } from '../events';
|
|
3
|
+
import { EngineProps } from '../engine';
|
|
4
|
+
type MouseMode = {
|
|
5
|
+
lock: false;
|
|
6
|
+
visible: boolean;
|
|
7
|
+
scrollBlock: boolean;
|
|
8
|
+
} | {
|
|
9
|
+
lock: true;
|
|
10
|
+
speed: number;
|
|
11
|
+
};
|
|
12
|
+
export type MouseSetMode = Partial<MouseMode> & {
|
|
13
|
+
lock: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Mouse input handling. Bound to canvas. Emits relative movement when pointer locked.
|
|
17
|
+
*/
|
|
18
|
+
export declare class Mouse {
|
|
19
|
+
private dispatch;
|
|
20
|
+
private pos;
|
|
21
|
+
private lastPos;
|
|
22
|
+
private buttons;
|
|
23
|
+
/** The canvas reference is the DOM / display canvas, this keeps
|
|
24
|
+
* track of the internal (apparent) canvas size.
|
|
25
|
+
*/
|
|
26
|
+
private canvasSize;
|
|
27
|
+
private canvas;
|
|
28
|
+
private lockedMode;
|
|
29
|
+
private unlockedMode;
|
|
30
|
+
private enableLock;
|
|
31
|
+
constructor(props: EngineProps<LikeMouseEvent>);
|
|
32
|
+
private handleMouseMove;
|
|
33
|
+
private handleMouseDown;
|
|
34
|
+
private handleMouseUp;
|
|
35
|
+
private handleWheel;
|
|
36
|
+
/** Mouse position, transformed to canvas pixels. */
|
|
37
|
+
getPosition(): Vector2;
|
|
38
|
+
/** Check if button is held. Button 1 = left, 2 = middle, 3 = right. */
|
|
39
|
+
isDown(button: MouseButton): boolean;
|
|
40
|
+
/** All currently held buttons. */
|
|
41
|
+
getPressedButtons(): Set<MouseButton>;
|
|
42
|
+
/**
|
|
43
|
+
* Set the current cursor mode.
|
|
44
|
+
*
|
|
45
|
+
* ### Normal mode
|
|
46
|
+
* Consider setting `scrollBlock` to false (default is true) if you want
|
|
47
|
+
* your element to blend into the webpage for freer scrolling.
|
|
48
|
+
*
|
|
49
|
+
* ```ts
|
|
50
|
+
* {
|
|
51
|
+
* lock: false,
|
|
52
|
+
* visible: true, // disable to hide cursor.
|
|
53
|
+
* scrollBlock: true, // disable scroll while hovering canvas. Default: true
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* ### Captured mode
|
|
58
|
+
* In locked mode, the cursor cannot escape the canvas.
|
|
59
|
+
* It also becomes invisible.
|
|
60
|
+
* However, it can move infinitely, sensitivity can be controlled,
|
|
61
|
+
* and the emulated cursor (in `pos` of {@link mousemoved}) can be freely repositioned.
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* {
|
|
65
|
+
* lock: true,
|
|
66
|
+
* speed: 1.0, // mouse sensitivity
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
* Avoid binding the `ESC` key in captured mode. This will exit the capture and
|
|
70
|
+
* reset mode to default.
|
|
71
|
+
*
|
|
72
|
+
* ### Note on `pos` vs `delta`
|
|
73
|
+
* Event {@link mousemoved} passes both `pos` and `delta` args.
|
|
74
|
+
*
|
|
75
|
+
* Though the emulated cursor in locked mode
|
|
76
|
+
* (locked mode doesn't natively track absolute position)
|
|
77
|
+
* may be stuck on canvas edges, the `delta` field always
|
|
78
|
+
* represents mouse movement, even against edges.
|
|
79
|
+
*/
|
|
80
|
+
setMode(mode: MouseSetMode): void;
|
|
81
|
+
getMode(): MouseMode;
|
|
82
|
+
/**
|
|
83
|
+
* Only applicable in capture mode -- sets the position
|
|
84
|
+
* of the emulated mouse.
|
|
85
|
+
*/
|
|
86
|
+
setCapturedPos(pos: Vector2): void;
|
|
87
|
+
/**
|
|
88
|
+
* Enable/disable pointer lock (capture).
|
|
89
|
+
*
|
|
90
|
+
* For more fine-grained control, use {@link setMode} which
|
|
91
|
+
* also documents behaviors more thoroughly.
|
|
92
|
+
*/
|
|
93
|
+
lockPointer(lock: boolean): void;
|
|
94
|
+
/**
|
|
95
|
+
* True when pointer is locked to canvas.
|
|
96
|
+
*/
|
|
97
|
+
isPointerLocked(): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* @returns whether the pointer is visible.
|
|
100
|
+
*/
|
|
101
|
+
isCursorVisible(): boolean;
|
|
102
|
+
/** I beleve you wanted to use `like.mouse.setMode({lock: true})`
|
|
103
|
+
* or `like.mouse.lockPointer().
|
|
104
|
+
*/
|
|
105
|
+
setRelativeMode?: never;
|
|
106
|
+
}
|
|
107
|
+
export {};
|
|
108
|
+
//# sourceMappingURL=mouse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mouse.d.ts","sourceRoot":"","sources":["../../src/input/mouse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,KAAK,WAAW,EAAmB,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAMxC,KAAK,SAAS,GACV;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAElE;;GAEG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,GAAG,CAAmB;IAC9B,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,OAAO,CAA0B;IACzC;;OAEG;IACH,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAoB;IAIlC,OAAO,CAAC,UAAU,CAAsD;IACxE,OAAO,CAAC,YAAY,CAAgF;IACpG,OAAO,CAAC,UAAU,CAAS;gBAEf,KAAK,EAAE,WAAW,CAAC,cAAc,CAAC;IAwC9C,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,WAAW;IAMnB,oDAAoD;IACpD,WAAW,IAAI,OAAO;IAItB,uEAAuE;IACvE,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO;IAIpC,kCAAkC;IAClC,iBAAiB,IAAI,GAAG,CAAC,WAAW,CAAC;IAIrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACH,OAAO,CAAC,IAAI,EAAE,YAAY;IAgB1B,OAAO,IAAI,SAAS;IAIpB;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,OAAO;IAQ3B;;;;;OAKG;IACH,WAAW,CAAC,IAAI,EAAE,OAAO;IAUzB;;OAEG;IACH,eAAe,IAAI,OAAO;IAI1B;;OAEG;IACH,eAAe,IAAI,OAAO;IAI1B;;OAEG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { Vec2 } from '../math/vector2';
|
|
2
|
+
const mouseButtons = ["left", "middle", "right"];
|
|
3
|
+
const numToButton = (i) => mouseButtons[i];
|
|
4
|
+
/**
|
|
5
|
+
* Mouse input handling. Bound to canvas. Emits relative movement when pointer locked.
|
|
6
|
+
*/
|
|
7
|
+
export class Mouse {
|
|
8
|
+
constructor(props) {
|
|
9
|
+
Object.defineProperty(this, "dispatch", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
configurable: true,
|
|
12
|
+
writable: true,
|
|
13
|
+
value: void 0
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(this, "pos", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
value: [0, 0]
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(this, "lastPos", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: [0, 0]
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(this, "buttons", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: new Set()
|
|
32
|
+
});
|
|
33
|
+
/** The canvas reference is the DOM / display canvas, this keeps
|
|
34
|
+
* track of the internal (apparent) canvas size.
|
|
35
|
+
*/
|
|
36
|
+
Object.defineProperty(this, "canvasSize", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
configurable: true,
|
|
39
|
+
writable: true,
|
|
40
|
+
value: [800, 600]
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(this, "canvas", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
configurable: true,
|
|
45
|
+
writable: true,
|
|
46
|
+
value: void 0
|
|
47
|
+
});
|
|
48
|
+
// We keep track of a locked mode and an unlocked mode, so that when capture changes
|
|
49
|
+
// we can use the settings from last time.
|
|
50
|
+
Object.defineProperty(this, "lockedMode", {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
configurable: true,
|
|
53
|
+
writable: true,
|
|
54
|
+
value: { lock: true, speed: 1 }
|
|
55
|
+
});
|
|
56
|
+
Object.defineProperty(this, "unlockedMode", {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
configurable: true,
|
|
59
|
+
writable: true,
|
|
60
|
+
value: { lock: false, visible: true, scrollBlock: true }
|
|
61
|
+
});
|
|
62
|
+
Object.defineProperty(this, "enableLock", {
|
|
63
|
+
enumerable: true,
|
|
64
|
+
configurable: true,
|
|
65
|
+
writable: true,
|
|
66
|
+
value: false
|
|
67
|
+
});
|
|
68
|
+
/** I beleve you wanted to use `like.mouse.setMode({lock: true})`
|
|
69
|
+
* or `like.mouse.lockPointer().
|
|
70
|
+
*/
|
|
71
|
+
Object.defineProperty(this, "setRelativeMode", {
|
|
72
|
+
enumerable: true,
|
|
73
|
+
configurable: true,
|
|
74
|
+
writable: true,
|
|
75
|
+
value: void 0
|
|
76
|
+
});
|
|
77
|
+
this.canvas = props.canvas;
|
|
78
|
+
this.dispatch = props.dispatch;
|
|
79
|
+
const { abort } = props;
|
|
80
|
+
this.canvas.addEventListener("like:mousemoved", this.handleMouseMove.bind(this), { signal: abort });
|
|
81
|
+
this.canvas.addEventListener("mousedown", this.handleMouseDown.bind(this), {
|
|
82
|
+
signal: abort,
|
|
83
|
+
});
|
|
84
|
+
window.addEventListener("mouseup", this.handleMouseUp.bind(this), {
|
|
85
|
+
signal: abort,
|
|
86
|
+
});
|
|
87
|
+
this.canvas.addEventListener("wheel", this.handleWheel.bind(this), {
|
|
88
|
+
passive: false,
|
|
89
|
+
signal: abort,
|
|
90
|
+
});
|
|
91
|
+
this.canvas.addEventListener("mouseleave", () => this.buttons.clear(), {
|
|
92
|
+
signal: abort,
|
|
93
|
+
});
|
|
94
|
+
this.canvas.addEventListener("pointerlockchanged", () => {
|
|
95
|
+
if (!this.isPointerLocked())
|
|
96
|
+
this.enableLock = false;
|
|
97
|
+
}, { signal: abort });
|
|
98
|
+
this.canvas.addEventListener("like:resizeCanvas", (e) => {
|
|
99
|
+
this.canvasSize = e.detail.size;
|
|
100
|
+
}, { signal: abort });
|
|
101
|
+
}
|
|
102
|
+
handleMouseMove(e) {
|
|
103
|
+
if (this.isPointerLocked() && this.enableLock) {
|
|
104
|
+
/** In pointer-lock mode, simulate a real cursor bounded by the canvas. */
|
|
105
|
+
this.setCapturedPos(Vec2.add(this.pos, Vec2.mul(e.detail.delta, this.lockedMode.speed)));
|
|
106
|
+
this.dispatch('mousemoved', [this.pos, e.detail.delta]);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
/** In non-pointer locked mode, calculate deltas ourselves. */
|
|
110
|
+
this.pos = e.detail.pos;
|
|
111
|
+
this.dispatch('mousemoved', [this.pos, Vec2.sub(this.pos, this.lastPos)]);
|
|
112
|
+
}
|
|
113
|
+
this.lastPos = this.pos;
|
|
114
|
+
}
|
|
115
|
+
handleMouseDown(e) {
|
|
116
|
+
// hack: ignore right clicks because they cause a refocus
|
|
117
|
+
if (!this.isPointerLocked() && e.button == 2)
|
|
118
|
+
return;
|
|
119
|
+
this.buttons.add(numToButton(e.button));
|
|
120
|
+
this.dispatch('mousepressed', [[e.offsetX, e.offsetY], numToButton(e.button)]);
|
|
121
|
+
this.canvas?.focus();
|
|
122
|
+
}
|
|
123
|
+
handleMouseUp(e) {
|
|
124
|
+
this.buttons.delete(numToButton(e.button));
|
|
125
|
+
this.dispatch('mousereleased', [[e.offsetX, e.offsetY], numToButton(e.button)]);
|
|
126
|
+
}
|
|
127
|
+
handleWheel(e) {
|
|
128
|
+
if (this.unlockedMode.scrollBlock) {
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Mouse position, transformed to canvas pixels. */
|
|
133
|
+
getPosition() {
|
|
134
|
+
return this.pos;
|
|
135
|
+
}
|
|
136
|
+
/** Check if button is held. Button 1 = left, 2 = middle, 3 = right. */
|
|
137
|
+
isDown(button) {
|
|
138
|
+
return this.buttons.has(button);
|
|
139
|
+
}
|
|
140
|
+
/** All currently held buttons. */
|
|
141
|
+
getPressedButtons() {
|
|
142
|
+
return new Set(this.buttons);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Set the current cursor mode.
|
|
146
|
+
*
|
|
147
|
+
* ### Normal mode
|
|
148
|
+
* Consider setting `scrollBlock` to false (default is true) if you want
|
|
149
|
+
* your element to blend into the webpage for freer scrolling.
|
|
150
|
+
*
|
|
151
|
+
* ```ts
|
|
152
|
+
* {
|
|
153
|
+
* lock: false,
|
|
154
|
+
* visible: true, // disable to hide cursor.
|
|
155
|
+
* scrollBlock: true, // disable scroll while hovering canvas. Default: true
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* ### Captured mode
|
|
160
|
+
* In locked mode, the cursor cannot escape the canvas.
|
|
161
|
+
* It also becomes invisible.
|
|
162
|
+
* However, it can move infinitely, sensitivity can be controlled,
|
|
163
|
+
* and the emulated cursor (in `pos` of {@link mousemoved}) can be freely repositioned.
|
|
164
|
+
*
|
|
165
|
+
* ```ts
|
|
166
|
+
* {
|
|
167
|
+
* lock: true,
|
|
168
|
+
* speed: 1.0, // mouse sensitivity
|
|
169
|
+
* }
|
|
170
|
+
* ```
|
|
171
|
+
* Avoid binding the `ESC` key in captured mode. This will exit the capture and
|
|
172
|
+
* reset mode to default.
|
|
173
|
+
*
|
|
174
|
+
* ### Note on `pos` vs `delta`
|
|
175
|
+
* Event {@link mousemoved} passes both `pos` and `delta` args.
|
|
176
|
+
*
|
|
177
|
+
* Though the emulated cursor in locked mode
|
|
178
|
+
* (locked mode doesn't natively track absolute position)
|
|
179
|
+
* may be stuck on canvas edges, the `delta` field always
|
|
180
|
+
* represents mouse movement, even against edges.
|
|
181
|
+
*/
|
|
182
|
+
setMode(mode) {
|
|
183
|
+
this.lockPointer(mode.lock);
|
|
184
|
+
if (mode.lock) {
|
|
185
|
+
this.lockedMode = {
|
|
186
|
+
...this.lockedMode,
|
|
187
|
+
...mode,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
this.unlockedMode = {
|
|
192
|
+
...this.unlockedMode,
|
|
193
|
+
...mode
|
|
194
|
+
};
|
|
195
|
+
this.canvas.style.cursor = this.unlockedMode.visible ? 'auto' : 'none';
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
getMode() {
|
|
199
|
+
return this.enableLock ? this.lockedMode : this.unlockedMode;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Only applicable in capture mode -- sets the position
|
|
203
|
+
* of the emulated mouse.
|
|
204
|
+
*/
|
|
205
|
+
setCapturedPos(pos) {
|
|
206
|
+
if (this.isPointerLocked()) {
|
|
207
|
+
this.pos = Vec2.clamp(pos, [0, 0], this.canvasSize);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
console.log("[Mouse] Attempt to set cursor position while not captured.");
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Enable/disable pointer lock (capture).
|
|
215
|
+
*
|
|
216
|
+
* For more fine-grained control, use {@link setMode} which
|
|
217
|
+
* also documents behaviors more thoroughly.
|
|
218
|
+
*/
|
|
219
|
+
lockPointer(lock) {
|
|
220
|
+
this.enableLock = lock;
|
|
221
|
+
const wasLocked = this.isPointerLocked();
|
|
222
|
+
if (lock && !wasLocked) {
|
|
223
|
+
this.canvas.requestPointerLock();
|
|
224
|
+
}
|
|
225
|
+
else if (!lock && wasLocked) {
|
|
226
|
+
document.exitPointerLock();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* True when pointer is locked to canvas.
|
|
231
|
+
*/
|
|
232
|
+
isPointerLocked() {
|
|
233
|
+
return document.pointerLockElement == this.canvas;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* @returns whether the pointer is visible.
|
|
237
|
+
*/
|
|
238
|
+
isCursorVisible() {
|
|
239
|
+
return this.enableLock || !this.unlockedMode.visible;
|
|
240
|
+
}
|
|
241
|
+
}
|