three-gamepad-controls 0.18.0 → 0.20.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.
- package/README.md +4 -1
- package/dist/gamepad-arcball-controls.d.ts +10 -19
- package/dist/gamepad-arcball-controls.js +39 -20
- package/dist/gamepad-drag-controls.d.ts +7 -21
- package/dist/gamepad-drag-controls.js +19 -13
- package/dist/gamepad-first-person-controls.d.ts +8 -19
- package/dist/gamepad-first-person-controls.js +29 -24
- package/dist/gamepad-fly-controls.d.ts +7 -18
- package/dist/gamepad-fly-controls.js +24 -13
- package/dist/gamepad-input.d.ts +10 -69
- package/dist/gamepad-input.js +18 -78
- package/dist/gamepad-manager.js +1 -1
- package/dist/gamepad-map-controls.js +17 -5
- package/dist/gamepad-orbit-controls.d.ts +10 -19
- package/dist/gamepad-orbit-controls.js +23 -16
- package/dist/gamepad-pointer-lock-controls.d.ts +7 -21
- package/dist/gamepad-pointer-lock-controls.js +22 -16
- package/dist/gamepad-stick-processing.d.ts +165 -0
- package/dist/gamepad-stick-processing.js +176 -0
- package/dist/gamepad-trackball-controls.d.ts +10 -19
- package/dist/gamepad-trackball-controls.js +34 -33
- package/dist/gamepad-transform-controls.d.ts +4 -13
- package/dist/gamepad-transform-controls.js +12 -8
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/package.json +1 -1
package/dist/gamepad-input.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GamepadStick, GamepadStickPipeline } from "./gamepad-stick-processing.js";
|
|
1
2
|
import { EventDispatcher } from "three";
|
|
2
3
|
//#region src/gamepad-input.d.ts
|
|
3
4
|
/**
|
|
@@ -23,39 +24,20 @@ type GamepadInputEventMap = {
|
|
|
23
24
|
gamepad: Gamepad;
|
|
24
25
|
};
|
|
25
26
|
};
|
|
26
|
-
/**
|
|
27
|
-
* Dead zone processing mode for two-dimensional stick reads.
|
|
28
|
-
*/
|
|
29
|
-
type GamepadDeadzoneMode = "axial" | "radial";
|
|
30
27
|
/**
|
|
31
28
|
* Configuration for {@link GamepadInput}.
|
|
32
29
|
*/
|
|
33
30
|
type GamepadInputOptions = {
|
|
34
31
|
/**
|
|
35
|
-
* Default
|
|
32
|
+
* Default dead zone threshold for {@link GamepadInput.axis} reads.
|
|
36
33
|
* @default 0.1
|
|
37
34
|
*/
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Default dead zone mode for stick reads.
|
|
41
|
-
* @default "axial"
|
|
42
|
-
*/
|
|
43
|
-
deadzoneMode: GamepadDeadzoneMode;
|
|
44
|
-
/**
|
|
45
|
-
* Whether stick reads rescale values outside the dead zone by default.
|
|
46
|
-
* @default false
|
|
47
|
-
*/
|
|
48
|
-
rescale: boolean;
|
|
49
|
-
/**
|
|
50
|
-
* Whether the horizontal component of stick reads is inverted by default.
|
|
51
|
-
* @default false
|
|
52
|
-
*/
|
|
53
|
-
invertX: boolean;
|
|
35
|
+
axisDeadzone: number;
|
|
54
36
|
/**
|
|
55
|
-
*
|
|
56
|
-
* @default
|
|
37
|
+
* Default stateless processing pipeline for stick reads.
|
|
38
|
+
* @default DEFAULT_GAMEPAD_STICK_PIPELINE
|
|
57
39
|
*/
|
|
58
|
-
|
|
40
|
+
stickPipeline: GamepadStickPipeline;
|
|
59
41
|
/**
|
|
60
42
|
* Browser-assigned gamepad slot to use.
|
|
61
43
|
*
|
|
@@ -76,47 +58,6 @@ type GamepadAxisOptions = {
|
|
|
76
58
|
*/
|
|
77
59
|
deadzone?: number;
|
|
78
60
|
};
|
|
79
|
-
/**
|
|
80
|
-
* Options for two-dimensional stick reads.
|
|
81
|
-
*/
|
|
82
|
-
type GamepadStickOptions = GamepadAxisOptions & {
|
|
83
|
-
/**
|
|
84
|
-
* Dead zone shape for this read.
|
|
85
|
-
*
|
|
86
|
-
* `"axial"` processes each axis independently, while `"radial"` processes
|
|
87
|
-
* the stick magnitude.
|
|
88
|
-
* @default "axial"
|
|
89
|
-
*/
|
|
90
|
-
deadzoneMode?: GamepadDeadzoneMode;
|
|
91
|
-
/**
|
|
92
|
-
* Whether to remap values outside the dead zone to the full output range.
|
|
93
|
-
* @default false
|
|
94
|
-
*/
|
|
95
|
-
rescale?: boolean;
|
|
96
|
-
/**
|
|
97
|
-
* Whether to invert the processed component from `xAxis`.
|
|
98
|
-
* @default false
|
|
99
|
-
*/
|
|
100
|
-
invertX?: boolean;
|
|
101
|
-
/**
|
|
102
|
-
* Whether to invert the processed component from `yAxis`.
|
|
103
|
-
* @default false
|
|
104
|
-
*/
|
|
105
|
-
invertY?: boolean;
|
|
106
|
-
};
|
|
107
|
-
/**
|
|
108
|
-
* Two-dimensional stick input after configured stick processing.
|
|
109
|
-
*/
|
|
110
|
-
type GamepadStick = {
|
|
111
|
-
/**
|
|
112
|
-
* Processed horizontal stick value.
|
|
113
|
-
*/
|
|
114
|
-
x: number;
|
|
115
|
-
/**
|
|
116
|
-
* Processed vertical stick value.
|
|
117
|
-
*/
|
|
118
|
-
y: number;
|
|
119
|
-
};
|
|
120
61
|
/**
|
|
121
62
|
* Gamepad input state reader for gameplay, menus, and custom actions.
|
|
122
63
|
*
|
|
@@ -214,14 +155,14 @@ declare class GamepadInput extends EventDispatcher<GamepadInputEventMap> {
|
|
|
214
155
|
*/
|
|
215
156
|
axis(axis: number, options?: GamepadAxisOptions): number;
|
|
216
157
|
/**
|
|
217
|
-
* Returns a two-axis stick after
|
|
158
|
+
* Returns a two-axis stick after applying a stateless processing pipeline.
|
|
218
159
|
*
|
|
219
160
|
* @param xAxis - Horizontal axis index.
|
|
220
161
|
* @param yAxis - Vertical axis index.
|
|
221
|
-
* @param
|
|
162
|
+
* @param pipeline - Optional pipeline replacing the instance default.
|
|
222
163
|
* @returns Object containing processed `x` and `y` values.
|
|
223
164
|
*/
|
|
224
|
-
stick(xAxis: number, yAxis: number,
|
|
165
|
+
stick(xAxis: number, yAxis: number, pipeline?: GamepadStickPipeline): GamepadStick;
|
|
225
166
|
/**
|
|
226
167
|
* Plays an effect through the active gamepad's primary vibration actuator.
|
|
227
168
|
*
|
|
@@ -245,4 +186,4 @@ declare class GamepadInput extends EventDispatcher<GamepadInputEventMap> {
|
|
|
245
186
|
resetVibration(): Promise<GamepadHapticsResult | null>;
|
|
246
187
|
}
|
|
247
188
|
//#endregion
|
|
248
|
-
export { GamepadAxisOptions,
|
|
189
|
+
export { GamepadAxisOptions, GamepadInput, GamepadInputEventMap, GamepadInputOptions };
|
package/dist/gamepad-input.js
CHANGED
|
@@ -1,71 +1,21 @@
|
|
|
1
1
|
import { isGamepadVibrationSupported, playGamepadVibrationEffect, resetGamepadVibration } from "./gamepad-haptics.js";
|
|
2
2
|
import { GamepadManager } from "./gamepad-manager.js";
|
|
3
|
+
import { DEFAULT_GAMEPAD_STICK_PIPELINE } from "./gamepad-stick-processing.js";
|
|
3
4
|
import { EventDispatcher } from "three";
|
|
4
5
|
//#region src/gamepad-input.ts
|
|
5
6
|
const DEFAULT_GAMEPAD_INPUT_OPTIONS = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
rescale: false,
|
|
9
|
-
invertX: false,
|
|
10
|
-
invertY: false
|
|
7
|
+
axisDeadzone: .1,
|
|
8
|
+
stickPipeline: DEFAULT_GAMEPAD_STICK_PIPELINE
|
|
11
9
|
};
|
|
12
10
|
/**
|
|
13
|
-
* Applies a dead zone
|
|
14
|
-
*
|
|
15
|
-
* @param magnitude - Non-negative input magnitude.
|
|
16
|
-
* @param threshold - Dead zone size.
|
|
17
|
-
* @returns Rescaled magnitude, or `0` when inside a fully closed dead zone.
|
|
18
|
-
*/
|
|
19
|
-
const rescaleGamepadDeadzoneMagnitude = (magnitude, threshold) => {
|
|
20
|
-
if (magnitude <= threshold || threshold >= 1) return 0;
|
|
21
|
-
return Math.min((magnitude - threshold) / (1 - threshold), 1);
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Applies an axial dead zone, optionally rescaling the remaining range.
|
|
11
|
+
* Applies a scalar dead zone without rescaling.
|
|
25
12
|
*
|
|
26
13
|
* @param value - Raw axis value.
|
|
27
14
|
* @param threshold - Dead zone size.
|
|
28
|
-
* @
|
|
29
|
-
* @returns Processed signed axis value.
|
|
15
|
+
* @returns The original value outside the dead zone, otherwise `0`.
|
|
30
16
|
*/
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
if (magnitude < threshold) return 0;
|
|
34
|
-
if (!rescale) return value;
|
|
35
|
-
return Math.sign(value) * rescaleGamepadDeadzoneMagnitude(magnitude, threshold);
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* Returns the stick unchanged, or centered if its magnitude is below the dead
|
|
39
|
-
* zone `threshold`.
|
|
40
|
-
*
|
|
41
|
-
* @param x - Raw horizontal stick value.
|
|
42
|
-
* @param y - Raw vertical stick value.
|
|
43
|
-
* @param threshold - Radial dead zone size.
|
|
44
|
-
* @param rescale - Whether to remap the remaining magnitude to `[0, 1]`.
|
|
45
|
-
* @returns The processed stick, or `{ x: 0, y: 0 }` inside the dead zone.
|
|
46
|
-
*/
|
|
47
|
-
const applyGamepadRadialDeadzone = (x, y, threshold, rescale) => {
|
|
48
|
-
const magnitude = Math.hypot(x, y);
|
|
49
|
-
if (magnitude < threshold) return {
|
|
50
|
-
x: 0,
|
|
51
|
-
y: 0
|
|
52
|
-
};
|
|
53
|
-
if (rescale) {
|
|
54
|
-
const rescaledMagnitude = rescaleGamepadDeadzoneMagnitude(magnitude, threshold);
|
|
55
|
-
if (rescaledMagnitude === 0 || magnitude === 0) return {
|
|
56
|
-
x: 0,
|
|
57
|
-
y: 0
|
|
58
|
-
};
|
|
59
|
-
const scale = rescaledMagnitude / magnitude;
|
|
60
|
-
return {
|
|
61
|
-
x: x * scale,
|
|
62
|
-
y: y * scale
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
x,
|
|
67
|
-
y
|
|
68
|
-
};
|
|
17
|
+
const applyGamepadAxisDeadzone = (value, threshold) => {
|
|
18
|
+
return Math.abs(value) < threshold ? 0 : value;
|
|
69
19
|
};
|
|
70
20
|
/**
|
|
71
21
|
* Returns whether a gamepad button is currently pressed.
|
|
@@ -276,33 +226,23 @@ var GamepadInput = class extends EventDispatcher {
|
|
|
276
226
|
*/
|
|
277
227
|
axis(axis, options) {
|
|
278
228
|
const value = this.#gamepad?.axes[axis] ?? 0;
|
|
279
|
-
return
|
|
229
|
+
return applyGamepadAxisDeadzone(value, this.#getAxisDeadzone(options));
|
|
280
230
|
}
|
|
281
231
|
/**
|
|
282
|
-
* Returns a two-axis stick after
|
|
232
|
+
* Returns a two-axis stick after applying a stateless processing pipeline.
|
|
283
233
|
*
|
|
284
234
|
* @param xAxis - Horizontal axis index.
|
|
285
235
|
* @param yAxis - Vertical axis index.
|
|
286
|
-
* @param
|
|
236
|
+
* @param pipeline - Optional pipeline replacing the instance default.
|
|
287
237
|
* @returns Object containing processed `x` and `y` values.
|
|
288
238
|
*/
|
|
289
|
-
stick(xAxis, yAxis,
|
|
290
|
-
const deadzoneMode = options?.deadzoneMode ?? this.#options.deadzoneMode;
|
|
291
|
-
const rescale = options?.rescale ?? this.#options.rescale;
|
|
292
|
-
const invertX = options?.invertX ?? this.#options.invertX;
|
|
293
|
-
const invertY = options?.invertY ?? this.#options.invertY;
|
|
294
|
-
const threshold = this.#getDeadzone(options);
|
|
239
|
+
stick(xAxis, yAxis, pipeline) {
|
|
295
240
|
const x = this.#gamepad?.axes[xAxis] ?? 0;
|
|
296
241
|
const y = this.#gamepad?.axes[yAxis] ?? 0;
|
|
297
|
-
|
|
298
|
-
x
|
|
299
|
-
y
|
|
300
|
-
};
|
|
301
|
-
if (!invertX && !invertY) return processed;
|
|
302
|
-
return {
|
|
303
|
-
x: processed.x === 0 ? 0 : invertX ? -processed.x : processed.x,
|
|
304
|
-
y: processed.y === 0 ? 0 : invertY ? -processed.y : processed.y
|
|
305
|
-
};
|
|
242
|
+
return (pipeline ?? this.#options.stickPipeline).process({
|
|
243
|
+
x,
|
|
244
|
+
y
|
|
245
|
+
});
|
|
306
246
|
}
|
|
307
247
|
/**
|
|
308
248
|
* Plays an effect through the active gamepad's primary vibration actuator.
|
|
@@ -391,13 +331,13 @@ var GamepadInput = class extends EventDispatcher {
|
|
|
391
331
|
this.#previousPressedButtons.clear();
|
|
392
332
|
}
|
|
393
333
|
/**
|
|
394
|
-
* Resolves the dead zone for a single
|
|
334
|
+
* Resolves the dead zone for a single-axis read.
|
|
395
335
|
*
|
|
396
336
|
* @param options - Optional per-read axis options.
|
|
397
337
|
* @returns The per-read dead zone when provided, otherwise the instance default.
|
|
398
338
|
*/
|
|
399
|
-
#
|
|
400
|
-
return options?.deadzone ?? this.#options.
|
|
339
|
+
#getAxisDeadzone(options) {
|
|
340
|
+
return options?.deadzone ?? this.#options.axisDeadzone;
|
|
401
341
|
}
|
|
402
342
|
};
|
|
403
343
|
//#endregion
|
package/dist/gamepad-manager.js
CHANGED
|
@@ -69,7 +69,7 @@ var GamepadManager = class {
|
|
|
69
69
|
* Polls the Gamepad API and refreshes the active gamepad snapshot.
|
|
70
70
|
*
|
|
71
71
|
* Polling re-resolves the browser slot so a disconnected device, a reused
|
|
72
|
-
* index, or an updated active device is observed before
|
|
72
|
+
* index, or an updated active device is observed before consumers read input.
|
|
73
73
|
*
|
|
74
74
|
* @returns The active gamepad and any connect/disconnect transition found.
|
|
75
75
|
*/
|
|
@@ -2,10 +2,14 @@ import { GAMEPAD_AXIS } from "./core.js";
|
|
|
2
2
|
import { GamepadOrbitControls } from "./gamepad-orbit-controls.js";
|
|
3
3
|
//#region src/gamepad-map-controls.ts
|
|
4
4
|
const DEFAULT_MAP_OPTIONS = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
panStick: {
|
|
6
|
+
xAxis: GAMEPAD_AXIS.LeftX,
|
|
7
|
+
yAxis: GAMEPAD_AXIS.LeftY
|
|
8
|
+
},
|
|
9
|
+
rotateStick: {
|
|
10
|
+
xAxis: GAMEPAD_AXIS.RightX,
|
|
11
|
+
yAxis: GAMEPAD_AXIS.RightY
|
|
12
|
+
}
|
|
9
13
|
};
|
|
10
14
|
/**
|
|
11
15
|
* Adds gamepad support to Three.js `MapControls`.
|
|
@@ -24,7 +28,15 @@ var GamepadMapControls = class extends GamepadOrbitControls {
|
|
|
24
28
|
constructor(controls, options) {
|
|
25
29
|
super(controls, {
|
|
26
30
|
...DEFAULT_MAP_OPTIONS,
|
|
27
|
-
...options
|
|
31
|
+
...options,
|
|
32
|
+
panStick: {
|
|
33
|
+
...DEFAULT_MAP_OPTIONS.panStick,
|
|
34
|
+
...options?.panStick
|
|
35
|
+
},
|
|
36
|
+
rotateStick: {
|
|
37
|
+
...DEFAULT_MAP_OPTIONS.rotateStick,
|
|
38
|
+
...options?.rotateStick
|
|
39
|
+
}
|
|
28
40
|
});
|
|
29
41
|
}
|
|
30
42
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
|
|
1
2
|
import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
|
|
2
3
|
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
|
3
4
|
//#region src/gamepad-orbit-controls.d.ts
|
|
@@ -23,30 +24,20 @@ type GamepadOrbitControlsOptions = GamepadControlsOptions & {
|
|
|
23
24
|
*/
|
|
24
25
|
zoomSpeed: number;
|
|
25
26
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @default
|
|
28
|
-
*/
|
|
29
|
-
deadzone: number;
|
|
30
|
-
/**
|
|
31
|
-
* Axis index for **horizontal** orbit rotation.
|
|
32
|
-
* @default 0 — Left stick X
|
|
27
|
+
* Stick binding used for orbit rotation.
|
|
28
|
+
* @default Left stick with the default stick pipeline
|
|
33
29
|
*/
|
|
34
|
-
|
|
30
|
+
rotateStick: GamepadStickBindingOptions;
|
|
35
31
|
/**
|
|
36
|
-
*
|
|
37
|
-
* @default
|
|
32
|
+
* Stick binding used for panning.
|
|
33
|
+
* @default Right stick with the default stick pipeline
|
|
38
34
|
*/
|
|
39
|
-
|
|
35
|
+
panStick: GamepadStickBindingOptions;
|
|
40
36
|
/**
|
|
41
|
-
*
|
|
42
|
-
* @default
|
|
43
|
-
*/
|
|
44
|
-
axisPanX: number;
|
|
45
|
-
/**
|
|
46
|
-
* Axis index for **vertical** panning.
|
|
47
|
-
* @default 3 — Right stick Y
|
|
37
|
+
* Dead zone threshold for analog trigger values.
|
|
38
|
+
* @default 0.1
|
|
48
39
|
*/
|
|
49
|
-
|
|
40
|
+
buttonDeadzone: number;
|
|
50
41
|
/**
|
|
51
42
|
* Button index for zooming **in** (analog trigger value used for proportional zoom).
|
|
52
43
|
* @default 7 — Right trigger
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
|
|
2
|
+
import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
|
|
2
3
|
import { GamepadControls } from "./gamepad-controls.js";
|
|
3
4
|
//#region src/gamepad-orbit-controls.ts
|
|
4
5
|
const DEFAULT_ORBIT_OPTIONS = {
|
|
5
6
|
rotateSpeed: 1,
|
|
6
7
|
panSpeed: 1,
|
|
7
8
|
zoomSpeed: 1,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
rotateStick: {
|
|
10
|
+
xAxis: GAMEPAD_AXIS.LeftX,
|
|
11
|
+
yAxis: GAMEPAD_AXIS.LeftY,
|
|
12
|
+
pipeline: DEFAULT_GAMEPAD_STICK_PIPELINE
|
|
13
|
+
},
|
|
14
|
+
panStick: {
|
|
15
|
+
xAxis: GAMEPAD_AXIS.RightX,
|
|
16
|
+
yAxis: GAMEPAD_AXIS.RightY,
|
|
17
|
+
pipeline: DEFAULT_GAMEPAD_STICK_PIPELINE
|
|
18
|
+
},
|
|
19
|
+
buttonDeadzone: .1,
|
|
13
20
|
buttonDollyIn: GAMEPAD_BUTTON.RightTrigger,
|
|
14
21
|
buttonDollyOut: GAMEPAD_BUTTON.LeftTrigger
|
|
15
22
|
};
|
|
@@ -32,7 +39,9 @@ var GamepadOrbitControls = class extends GamepadControls {
|
|
|
32
39
|
this.#controls = controls;
|
|
33
40
|
this.#options = {
|
|
34
41
|
...DEFAULT_ORBIT_OPTIONS,
|
|
35
|
-
...options
|
|
42
|
+
...options,
|
|
43
|
+
rotateStick: resolveGamepadStickBinding(DEFAULT_ORBIT_OPTIONS.rotateStick, options?.rotateStick),
|
|
44
|
+
panStick: resolveGamepadStickBinding(DEFAULT_ORBIT_OPTIONS.panStick, options?.panStick)
|
|
36
45
|
};
|
|
37
46
|
}
|
|
38
47
|
/**
|
|
@@ -41,19 +50,17 @@ var GamepadOrbitControls = class extends GamepadControls {
|
|
|
41
50
|
* @param deltaTime - Seconds since the last frame.
|
|
42
51
|
*/
|
|
43
52
|
onUpdate(deltaTime) {
|
|
44
|
-
const { rotateSpeed, panSpeed, zoomSpeed,
|
|
53
|
+
const { rotateSpeed, panSpeed, zoomSpeed, rotateStick, panStick, buttonDeadzone, buttonDollyIn, buttonDollyOut } = this.#options;
|
|
45
54
|
const input = this.gamepadInput;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const panY = input.axis(axisPanY, { deadzone });
|
|
52
|
-
if (panX !== 0 || panY !== 0) this.#controls.pan(panX * panSpeed * deltaTime * 500, panY * panSpeed * deltaTime * 500);
|
|
55
|
+
const rotate = input.stick(rotateStick.xAxis, rotateStick.yAxis, rotateStick.pipeline);
|
|
56
|
+
if (rotate.x !== 0) this.#controls.rotateLeft(rotate.x * rotateSpeed * deltaTime * Math.PI);
|
|
57
|
+
if (rotate.y !== 0) this.#controls.rotateUp(rotate.y * rotateSpeed * deltaTime * Math.PI);
|
|
58
|
+
const pan = input.stick(panStick.xAxis, panStick.yAxis, panStick.pipeline);
|
|
59
|
+
if (pan.x !== 0 || pan.y !== 0) this.#controls.pan(pan.x * panSpeed * deltaTime * 500, pan.y * panSpeed * deltaTime * 500);
|
|
53
60
|
const triggerIn = input.buttonValue(buttonDollyIn);
|
|
54
61
|
const triggerOut = input.buttonValue(buttonDollyOut);
|
|
55
|
-
if (triggerIn >
|
|
56
|
-
if (triggerOut >
|
|
62
|
+
if (triggerIn > buttonDeadzone) this.#controls.dollyIn(1 / (1 + zoomSpeed * triggerIn * deltaTime));
|
|
63
|
+
if (triggerOut > buttonDeadzone) this.#controls.dollyOut(1 / (1 + zoomSpeed * triggerOut * deltaTime));
|
|
57
64
|
}
|
|
58
65
|
};
|
|
59
66
|
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
|
|
1
2
|
import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
|
|
2
3
|
import { PointerLockControls } from "three/addons/controls/PointerLockControls.js";
|
|
3
4
|
//#region src/gamepad-pointer-lock-controls.d.ts
|
|
@@ -18,30 +19,15 @@ type GamepadPointerLockControlsOptions = GamepadControlsOptions & {
|
|
|
18
19
|
*/
|
|
19
20
|
lookSpeed: number;
|
|
20
21
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @default
|
|
22
|
+
* Stick binding used for horizontal and forward movement.
|
|
23
|
+
* @default Left stick with the default stick pipeline
|
|
23
24
|
*/
|
|
24
|
-
|
|
25
|
+
moveStick: GamepadStickBindingOptions;
|
|
25
26
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @default
|
|
27
|
+
* Stick binding used for yaw and pitch.
|
|
28
|
+
* @default Right stick with the default stick pipeline
|
|
28
29
|
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Axis index for **right / left** strafe movement.
|
|
32
|
-
* @default 0 — Left stick X
|
|
33
|
-
*/
|
|
34
|
-
axisMoveRight: number;
|
|
35
|
-
/**
|
|
36
|
-
* Axis index for **horizontal** camera look (yaw).
|
|
37
|
-
* @default 2 — Right stick X
|
|
38
|
-
*/
|
|
39
|
-
axisLookX: number;
|
|
40
|
-
/**
|
|
41
|
-
* Axis index for **vertical** camera look (pitch).
|
|
42
|
-
* @default 3 — Right stick Y
|
|
43
|
-
*/
|
|
44
|
-
axisLookY: number;
|
|
30
|
+
lookStick: GamepadStickBindingOptions;
|
|
45
31
|
};
|
|
46
32
|
/**
|
|
47
33
|
* Adds gamepad support to Three.js `PointerLockControls`.
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { GAMEPAD_AXIS } from "./core.js";
|
|
2
|
+
import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
|
|
2
3
|
import { GamepadControls } from "./gamepad-controls.js";
|
|
3
4
|
import { Euler } from "three";
|
|
4
5
|
//#region src/gamepad-pointer-lock-controls.ts
|
|
5
6
|
const DEFAULT_POINTER_LOCK_OPTIONS = {
|
|
6
7
|
moveSpeed: 5,
|
|
7
8
|
lookSpeed: 1,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
moveStick: {
|
|
10
|
+
xAxis: GAMEPAD_AXIS.LeftX,
|
|
11
|
+
yAxis: GAMEPAD_AXIS.LeftY,
|
|
12
|
+
pipeline: DEFAULT_GAMEPAD_STICK_PIPELINE
|
|
13
|
+
},
|
|
14
|
+
lookStick: {
|
|
15
|
+
xAxis: GAMEPAD_AXIS.RightX,
|
|
16
|
+
yAxis: GAMEPAD_AXIS.RightY,
|
|
17
|
+
pipeline: DEFAULT_GAMEPAD_STICK_PIPELINE
|
|
18
|
+
}
|
|
13
19
|
};
|
|
14
20
|
/**
|
|
15
21
|
* Adds gamepad support to Three.js `PointerLockControls`.
|
|
@@ -32,7 +38,9 @@ var GamepadPointerLockControls = class extends GamepadControls {
|
|
|
32
38
|
this.#controls = controls;
|
|
33
39
|
this.#options = {
|
|
34
40
|
...DEFAULT_POINTER_LOCK_OPTIONS,
|
|
35
|
-
...options
|
|
41
|
+
...options,
|
|
42
|
+
moveStick: resolveGamepadStickBinding(DEFAULT_POINTER_LOCK_OPTIONS.moveStick, options?.moveStick),
|
|
43
|
+
lookStick: resolveGamepadStickBinding(DEFAULT_POINTER_LOCK_OPTIONS.lookStick, options?.lookStick)
|
|
36
44
|
};
|
|
37
45
|
this.#euler = new Euler(0, 0, 0, "YXZ");
|
|
38
46
|
}
|
|
@@ -42,20 +50,18 @@ var GamepadPointerLockControls = class extends GamepadControls {
|
|
|
42
50
|
* @param deltaTime - Seconds since the last frame.
|
|
43
51
|
*/
|
|
44
52
|
onUpdate(deltaTime) {
|
|
45
|
-
const { moveSpeed, lookSpeed,
|
|
53
|
+
const { moveSpeed, lookSpeed, moveStick, lookStick } = this.#options;
|
|
46
54
|
const input = this.gamepadInput;
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const lookY = input.axis(axisLookY, { deadzone });
|
|
53
|
-
if (lookX !== 0 || lookY !== 0) {
|
|
55
|
+
const move = input.stick(moveStick.xAxis, moveStick.yAxis, moveStick.pipeline);
|
|
56
|
+
if (move.y !== 0) this.#controls.moveForward(-move.y * moveSpeed * deltaTime);
|
|
57
|
+
if (move.x !== 0) this.#controls.moveRight(move.x * moveSpeed * deltaTime);
|
|
58
|
+
const look = input.stick(lookStick.xAxis, lookStick.yAxis, lookStick.pipeline);
|
|
59
|
+
if (look.x !== 0 || look.y !== 0) {
|
|
54
60
|
const camera = this.#controls.object;
|
|
55
61
|
const scale = lookSpeed * this.#controls.pointerSpeed * deltaTime * Math.PI;
|
|
56
62
|
this.#euler.setFromQuaternion(camera.quaternion);
|
|
57
|
-
this.#euler.y -=
|
|
58
|
-
this.#euler.x -=
|
|
63
|
+
this.#euler.y -= look.x * scale;
|
|
64
|
+
this.#euler.x -= look.y * scale;
|
|
59
65
|
this.#euler.x = Math.max(Math.PI / 2 - this.#controls.maxPolarAngle, Math.min(Math.PI / 2 - this.#controls.minPolarAngle, this.#euler.x));
|
|
60
66
|
camera.quaternion.setFromEuler(this.#euler);
|
|
61
67
|
}
|