@pmndrs/viverse 0.2.0 → 0.2.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/dist/animation/bone-map.d.ts +4 -0
- package/dist/animation/bone-map.js +11 -0
- package/dist/animation/default.d.ts +9 -1
- package/dist/animation/default.js +16 -9
- package/dist/animation/index.d.ts +8 -13
- package/dist/animation/index.js +61 -39
- package/dist/animation/mask.d.ts +4 -1
- package/dist/animation/mask.js +50 -0
- package/dist/camera.d.ts +6 -2
- package/dist/camera.js +22 -7
- package/dist/input/action.d.ts +41 -0
- package/dist/input/action.js +97 -0
- package/dist/input/index.d.ts +12 -26
- package/dist/input/index.js +17 -70
- package/dist/input/keyboard.d.ts +28 -5
- package/dist/input/keyboard.js +83 -69
- package/dist/input/pointer-capture.d.ts +5 -10
- package/dist/input/pointer-capture.js +9 -28
- package/dist/input/pointer-lock.d.ts +5 -10
- package/dist/input/pointer-lock.js +7 -28
- package/dist/input/screen-joystick.d.ts +11 -6
- package/dist/input/screen-joystick.js +31 -34
- package/dist/input/screen-jump-button.d.ts +2 -4
- package/dist/input/screen-jump-button.js +7 -12
- package/dist/model/index.d.ts +1 -2
- package/dist/simple-character/apply-input-options.d.ts +2 -0
- package/dist/simple-character/apply-input-options.js +28 -0
- package/dist/simple-character/index.d.ts +21 -6
- package/dist/simple-character/index.js +12 -17
- package/dist/simple-character/state/jump-down.js +2 -1
- package/dist/simple-character/state/jump-forward.js +4 -2
- package/dist/simple-character/state/jump-loop.js +2 -1
- package/dist/simple-character/state/jump-start.js +2 -2
- package/dist/simple-character/state/jump-up.js +4 -2
- package/dist/simple-character/state/movement.js +12 -8
- package/dist/simple-character/update-input-velocity.d.ts +1 -2
- package/dist/simple-character/update-input-velocity.js +4 -4
- package/dist/utils.d.ts +5 -5
- package/dist/utils.js +15 -6
- package/package.json +2 -2
- package/dist/animation/bvh.d.ts +0 -4
- package/dist/animation/bvh.js +0 -8
- package/dist/animation/fbx.d.ts +0 -4
- package/dist/animation/fbx.js +0 -8
- package/dist/animation/gltf.d.ts +0 -3
- package/dist/animation/gltf.js +0 -8
- package/dist/animation/vrma.d.ts +0 -3
- package/dist/animation/vrma.js +0 -8
package/dist/input/index.js
CHANGED
|
@@ -1,77 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
add(input) {
|
|
8
|
-
this.inputs.push(input);
|
|
9
|
-
}
|
|
10
|
-
remove(input) {
|
|
11
|
-
const index = this.inputs.indexOf(input);
|
|
12
|
-
if (index === -1) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
this.inputs.splice(index, 1);
|
|
16
|
-
}
|
|
17
|
-
dispose() {
|
|
18
|
-
this.inputs.forEach((input) => input.dispose?.());
|
|
19
|
-
this.inputs.length = 0;
|
|
20
|
-
}
|
|
21
|
-
get(field) {
|
|
22
|
-
let current;
|
|
23
|
-
for (const input of this.inputs) {
|
|
24
|
-
const result = input.get(field, this.options);
|
|
25
|
-
if (result == null) {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
if (current == undefined) {
|
|
29
|
-
current = result;
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
current = field.combine(current, result);
|
|
33
|
-
}
|
|
34
|
-
return current ?? field.default;
|
|
1
|
+
import { EventAction, StateAction, DeltaAction } from './action.js';
|
|
2
|
+
export function BooleanOr(...values) {
|
|
3
|
+
let value = false;
|
|
4
|
+
for (let i = 0; i < values.length; i++) {
|
|
5
|
+
value ||= values[i];
|
|
35
6
|
}
|
|
7
|
+
return value;
|
|
36
8
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
export const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export const
|
|
46
|
-
|
|
47
|
-
combine: Math.max,
|
|
48
|
-
};
|
|
49
|
-
export const MoveRightField = {
|
|
50
|
-
default: 0,
|
|
51
|
-
combine: Math.max,
|
|
52
|
-
};
|
|
53
|
-
export const LastTimeJumpPressedField = {
|
|
54
|
-
default: null,
|
|
55
|
-
combine: (v1, v2) => (v1 == null && v2 == null ? null : Math.min(v1 ?? Infinity, v2 ?? Infinity)),
|
|
56
|
-
};
|
|
57
|
-
export const RunField = {
|
|
58
|
-
default: false,
|
|
59
|
-
combine: (v1, v2) => v1 || v2,
|
|
60
|
-
};
|
|
61
|
-
export const DeltaZoomField = {
|
|
62
|
-
default: 0,
|
|
63
|
-
combine: Math.max,
|
|
64
|
-
};
|
|
65
|
-
export const DeltaYawField = {
|
|
66
|
-
default: 0,
|
|
67
|
-
combine: Math.max,
|
|
68
|
-
};
|
|
69
|
-
export const DeltaPitchField = {
|
|
70
|
-
default: 0,
|
|
71
|
-
combine: Math.max,
|
|
72
|
-
};
|
|
9
|
+
const sum = (...values) => values.reduce((a, b) => a + b, 0);
|
|
10
|
+
export const MoveForwardAction = new StateAction(Math.max, 0);
|
|
11
|
+
export const MoveBackwardAction = new StateAction(Math.max, 0);
|
|
12
|
+
export const MoveLeftAction = new StateAction(Math.max, 0);
|
|
13
|
+
export const MoveRightAction = new StateAction(Math.max, 0);
|
|
14
|
+
export const RunAction = new StateAction(BooleanOr, false);
|
|
15
|
+
export const JumpAction = new EventAction();
|
|
16
|
+
export const ZoomAction = new DeltaAction(sum, 0);
|
|
17
|
+
export const RotateYawAction = new DeltaAction(sum, 0);
|
|
18
|
+
export const RotatePitchAction = new DeltaAction(sum, 0);
|
|
73
19
|
export * from './pointer-lock.js';
|
|
74
20
|
export * from './pointer-capture.js';
|
|
75
21
|
export * from './keyboard.js';
|
|
76
22
|
export * from './screen-joystick.js';
|
|
77
23
|
export * from './screen-jump-button.js';
|
|
24
|
+
export * from './action.js';
|
package/dist/input/keyboard.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EventAction, StateAction } from './index.js';
|
|
2
|
+
export declare class KeyboardInput {
|
|
3
|
+
private readonly domElement;
|
|
4
|
+
private readonly abortController;
|
|
5
|
+
options: Partial<{
|
|
6
|
+
keys: Array<string>;
|
|
7
|
+
}>;
|
|
8
|
+
abortSignal: AbortSignal;
|
|
9
|
+
private readonly pressedKeys;
|
|
10
|
+
constructor(domElement: HTMLElement);
|
|
11
|
+
bindEvent(action: EventAction): void;
|
|
12
|
+
bindValue(action: StateAction<boolean>): void;
|
|
13
|
+
bindValue<T>(action: StateAction<T>, map: (value: boolean) => T): void;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
}
|
|
2
16
|
export type LocomotionKeyboardInputOptions = {
|
|
3
17
|
keyboardMoveForwardKeys?: Array<string>;
|
|
4
18
|
keyboardMoveBackwardKeys?: Array<string>;
|
|
@@ -7,10 +21,19 @@ export type LocomotionKeyboardInputOptions = {
|
|
|
7
21
|
keyboardRunKeys?: Array<string>;
|
|
8
22
|
keyboardJumpKeys?: Array<string>;
|
|
9
23
|
};
|
|
10
|
-
export declare
|
|
11
|
-
|
|
12
|
-
|
|
24
|
+
export declare const DefaultMoveForwardKeys: string[];
|
|
25
|
+
export declare const DefaultMoveBackwardKeys: string[];
|
|
26
|
+
export declare const DefaultMoveLeftKeys: string[];
|
|
27
|
+
export declare const DefaultMoveRightKeys: string[];
|
|
28
|
+
export declare const DefaultRunKeys: string[];
|
|
29
|
+
export declare const DefaultJumpKeys: string[];
|
|
30
|
+
export declare class LocomotionKeyboardInput {
|
|
31
|
+
forward: KeyboardInput;
|
|
32
|
+
left: KeyboardInput;
|
|
33
|
+
right: KeyboardInput;
|
|
34
|
+
backward: KeyboardInput;
|
|
35
|
+
jump: KeyboardInput;
|
|
36
|
+
run: KeyboardInput;
|
|
13
37
|
constructor(domElement: HTMLElement);
|
|
14
|
-
get<T>(field: InputField<T>, options: LocomotionKeyboardInputOptions): T | undefined;
|
|
15
38
|
dispose(): void;
|
|
16
39
|
}
|
package/dist/input/keyboard.js
CHANGED
|
@@ -1,82 +1,96 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const DefaultMoveLeftKeys = ['KeyA'];
|
|
5
|
-
const DefaultMoveRightKeys = ['KeyD'];
|
|
6
|
-
const DefaultRunKeys = ['ShiftRight', 'ShiftLeft'];
|
|
7
|
-
const DefaultJumpKeys = ['Space'];
|
|
8
|
-
export class LocomotionKeyboardInput {
|
|
1
|
+
import { JumpAction, MoveBackwardAction, MoveForwardAction, MoveLeftAction, MoveRightAction, RunAction, } from './index.js';
|
|
2
|
+
export class KeyboardInput {
|
|
3
|
+
domElement;
|
|
9
4
|
abortController = new AbortController();
|
|
10
|
-
|
|
5
|
+
options = {};
|
|
6
|
+
abortSignal = this.abortController.signal;
|
|
7
|
+
pressedKeys = new Set();
|
|
11
8
|
constructor(domElement) {
|
|
12
|
-
domElement
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
this.domElement = domElement;
|
|
10
|
+
}
|
|
11
|
+
bindEvent(action) {
|
|
12
|
+
const isWatched = (e) => this.options.keys == null || this.options.keys.length === 0 || this.options.keys.includes(e.code);
|
|
13
|
+
this.domElement.addEventListener('keydown', (e) => {
|
|
14
|
+
if (!isWatched(e) || e.repeat) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
action.emit({});
|
|
18
|
+
}, { signal: this.abortController.signal });
|
|
19
|
+
}
|
|
20
|
+
bindValue(action, map) {
|
|
21
|
+
const writer = action.createWriter(this.abortSignal);
|
|
22
|
+
const isWatched = (e) => this.options.keys == null || this.options.keys.length === 0 || this.options.keys.includes(e.code);
|
|
23
|
+
let isPressed = false;
|
|
24
|
+
const write = (value) => {
|
|
25
|
+
if (isPressed === value) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
isPressed = value;
|
|
29
|
+
writer.write(map?.(value) ?? value);
|
|
30
|
+
};
|
|
31
|
+
this.domElement.tabIndex = 0;
|
|
32
|
+
this.domElement.addEventListener('keydown', (e) => {
|
|
33
|
+
if (!isWatched(e)) {
|
|
34
|
+
return;
|
|
18
35
|
}
|
|
19
|
-
|
|
20
|
-
|
|
36
|
+
const wasEmpty = this.pressedKeys.size === 0;
|
|
37
|
+
this.pressedKeys.add(e.code);
|
|
38
|
+
if (wasEmpty && this.pressedKeys.size > 0) {
|
|
39
|
+
write(true);
|
|
21
40
|
}
|
|
22
|
-
}, {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
let state = this.keyState.get(event.code);
|
|
27
|
-
const now = performance.now() / 1000;
|
|
28
|
-
if (state == null) {
|
|
29
|
-
this.keyState.set(event.code, (state = { releaseTime: now }));
|
|
41
|
+
}, { signal: this.abortController.signal });
|
|
42
|
+
this.domElement.addEventListener('keyup', (e) => {
|
|
43
|
+
if (!isWatched(e)) {
|
|
44
|
+
return;
|
|
30
45
|
}
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
if (this.pressedKeys.delete(e.code) && this.pressedKeys.size === 0) {
|
|
47
|
+
write(false);
|
|
33
48
|
}
|
|
34
|
-
}, {
|
|
35
|
-
signal: this.abortController.signal,
|
|
36
|
-
});
|
|
49
|
+
}, { signal: this.abortController.signal });
|
|
37
50
|
// Handle focus loss to clear pressed keys
|
|
38
|
-
domElement.addEventListener('blur', () =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
get(field, options) {
|
|
43
|
-
if (field === LastTimeJumpPressedField) {
|
|
44
|
-
const jumpKeys = options.keyboardJumpKeys ?? DefaultJumpKeys;
|
|
45
|
-
const pressed = jumpKeys
|
|
46
|
-
.map((key) => this.keyState.get(key)?.pressTime ?? null)
|
|
47
|
-
.filter((t) => t != null);
|
|
48
|
-
return (pressed.length > 0 ? Math.max(...pressed) : null);
|
|
49
|
-
}
|
|
50
|
-
let keys;
|
|
51
|
-
switch (field) {
|
|
52
|
-
case MoveForwardField:
|
|
53
|
-
keys = options.keyboardMoveForwardKeys ?? DefaultMoveForwardKeys;
|
|
54
|
-
break;
|
|
55
|
-
case MoveBackwardField:
|
|
56
|
-
keys = options.keyboardMoveBackwardKeys ?? DefaultMoveBackwardKeys;
|
|
57
|
-
break;
|
|
58
|
-
case MoveLeftField:
|
|
59
|
-
keys = options.keyboardMoveLeftKeys ?? DefaultMoveLeftKeys;
|
|
60
|
-
break;
|
|
61
|
-
case MoveRightField:
|
|
62
|
-
keys = options.keyboardMoveRightKeys ?? DefaultMoveRightKeys;
|
|
63
|
-
break;
|
|
64
|
-
case RunField:
|
|
65
|
-
keys = options.keyboardRunKeys ?? DefaultRunKeys;
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
if (keys == null) {
|
|
69
|
-
return undefined;
|
|
70
|
-
}
|
|
71
|
-
return keys.some((key) => {
|
|
72
|
-
const state = this.keyState.get(key);
|
|
73
|
-
if (state?.pressTime == null) {
|
|
74
|
-
return false;
|
|
51
|
+
this.domElement.addEventListener('blur', () => {
|
|
52
|
+
if (this.pressedKeys.size > 0) {
|
|
53
|
+
this.pressedKeys.clear();
|
|
54
|
+
write(false);
|
|
75
55
|
}
|
|
76
|
-
|
|
77
|
-
});
|
|
56
|
+
}, { signal: this.abortController.signal });
|
|
78
57
|
}
|
|
79
58
|
dispose() {
|
|
80
59
|
this.abortController.abort();
|
|
81
60
|
}
|
|
82
61
|
}
|
|
62
|
+
export const DefaultMoveForwardKeys = ['KeyW'];
|
|
63
|
+
export const DefaultMoveBackwardKeys = ['KeyS'];
|
|
64
|
+
export const DefaultMoveLeftKeys = ['KeyA'];
|
|
65
|
+
export const DefaultMoveRightKeys = ['KeyD'];
|
|
66
|
+
export const DefaultRunKeys = ['ShiftRight', 'ShiftLeft'];
|
|
67
|
+
export const DefaultJumpKeys = ['Space'];
|
|
68
|
+
export class LocomotionKeyboardInput {
|
|
69
|
+
forward;
|
|
70
|
+
left;
|
|
71
|
+
right;
|
|
72
|
+
backward;
|
|
73
|
+
jump;
|
|
74
|
+
run;
|
|
75
|
+
constructor(domElement) {
|
|
76
|
+
this.forward = new KeyboardInput(domElement);
|
|
77
|
+
this.forward.options.keys = DefaultMoveForwardKeys;
|
|
78
|
+
this.forward.bindValue(MoveForwardAction, (isPressed) => (isPressed ? 1 : 0));
|
|
79
|
+
this.left = new KeyboardInput(domElement);
|
|
80
|
+
this.left.options.keys = DefaultMoveLeftKeys;
|
|
81
|
+
this.left.bindValue(MoveLeftAction, (isPressed) => (isPressed ? 1 : 0));
|
|
82
|
+
this.right = new KeyboardInput(domElement);
|
|
83
|
+
this.right.options.keys = DefaultMoveRightKeys;
|
|
84
|
+
this.right.bindValue(MoveRightAction, (isPressed) => (isPressed ? 1 : 0));
|
|
85
|
+
this.backward = new KeyboardInput(domElement);
|
|
86
|
+
this.backward.options.keys = DefaultMoveBackwardKeys;
|
|
87
|
+
this.backward.bindValue(MoveBackwardAction, (isPressed) => (isPressed ? 1 : 0));
|
|
88
|
+
this.jump = new KeyboardInput(domElement);
|
|
89
|
+
this.jump.options.keys = DefaultJumpKeys;
|
|
90
|
+
this.jump.bindEvent(JumpAction);
|
|
91
|
+
this.run = new KeyboardInput(domElement);
|
|
92
|
+
this.run.options.keys = DefaultRunKeys;
|
|
93
|
+
this.run.bindValue(RunAction);
|
|
94
|
+
}
|
|
95
|
+
dispose() { }
|
|
96
|
+
}
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import { Input, InputField } from './index.js';
|
|
2
|
-
export type PointerCaptureInputOptions = {
|
|
3
|
-
pointerCaptureRotationSpeed?: number;
|
|
4
|
-
pointerCaptureZoomSpeed?: number;
|
|
5
|
-
};
|
|
6
1
|
/**
|
|
7
2
|
* @requires to manually execute `domElement.setPointerCapture(pointerId)` on pointerdown
|
|
8
3
|
*/
|
|
9
|
-
export declare class PointerCaptureInput
|
|
4
|
+
export declare class PointerCaptureInput {
|
|
10
5
|
private readonly domElement;
|
|
11
6
|
private readonly abortController;
|
|
12
|
-
private deltaZoom;
|
|
13
|
-
private deltaYaw;
|
|
14
|
-
private deltaPitch;
|
|
15
7
|
private activePointers;
|
|
16
8
|
private lastPinchDist;
|
|
9
|
+
options: {
|
|
10
|
+
rotationSpeed?: number;
|
|
11
|
+
zoomSpeed?: number;
|
|
12
|
+
};
|
|
17
13
|
constructor(domElement: HTMLElement);
|
|
18
|
-
get<T>(field: InputField<T>, options: PointerCaptureInputOptions): T | undefined;
|
|
19
14
|
dispose(): void;
|
|
20
15
|
}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RotatePitchAction, RotateYawAction, ZoomAction } from './index.js';
|
|
2
2
|
/**
|
|
3
3
|
* @requires to manually execute `domElement.setPointerCapture(pointerId)` on pointerdown
|
|
4
4
|
*/
|
|
5
5
|
export class PointerCaptureInput {
|
|
6
6
|
domElement;
|
|
7
7
|
abortController = new AbortController();
|
|
8
|
-
deltaZoom = 0;
|
|
9
|
-
deltaYaw = 0;
|
|
10
|
-
deltaPitch = 0;
|
|
11
8
|
activePointers = new Map();
|
|
12
9
|
lastPinchDist = null;
|
|
10
|
+
options = {};
|
|
13
11
|
constructor(domElement) {
|
|
14
12
|
this.domElement = domElement;
|
|
15
13
|
domElement.addEventListener('pointerdown', (event) => {
|
|
@@ -31,14 +29,16 @@ export class PointerCaptureInput {
|
|
|
31
29
|
const pts = Array.from(this.activePointers.values());
|
|
32
30
|
if (this.lastPinchDist != null) {
|
|
33
31
|
const d = Math.hypot(pts[0].x - pts[1].x, pts[0].y - pts[1].y);
|
|
34
|
-
|
|
32
|
+
const zoomSpeed = this.options.zoomSpeed ?? 0.0001;
|
|
33
|
+
ZoomAction.write((this.lastPinchDist - d) * zoomSpeed);
|
|
35
34
|
this.lastPinchDist = d;
|
|
36
35
|
}
|
|
37
36
|
event.preventDefault();
|
|
38
37
|
return;
|
|
39
38
|
}
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const rotationSpeed = this.options.rotationSpeed ?? 0.4;
|
|
40
|
+
RotateYawAction.write(-(event.movementX / window.innerHeight) * rotationSpeed);
|
|
41
|
+
RotatePitchAction.write(-(event.movementY / window.innerHeight) * rotationSpeed);
|
|
42
42
|
}, {
|
|
43
43
|
signal: this.abortController.signal,
|
|
44
44
|
});
|
|
@@ -62,31 +62,12 @@ export class PointerCaptureInput {
|
|
|
62
62
|
});
|
|
63
63
|
domElement.addEventListener('wheel', (event) => {
|
|
64
64
|
event.preventDefault();
|
|
65
|
-
this.
|
|
65
|
+
const zoomSpeed = this.options.zoomSpeed ?? 0.0001;
|
|
66
|
+
ZoomAction.write(event.deltaY * zoomSpeed);
|
|
66
67
|
}, {
|
|
67
68
|
signal: this.abortController.signal,
|
|
68
69
|
});
|
|
69
70
|
}
|
|
70
|
-
get(field, options) {
|
|
71
|
-
const rotationSpeed = options.pointerCaptureRotationSpeed ?? 0.4;
|
|
72
|
-
const zoomSpeed = options.pointerCaptureZoomSpeed ?? 0.0001;
|
|
73
|
-
let result;
|
|
74
|
-
switch (field) {
|
|
75
|
-
case DeltaPitchField:
|
|
76
|
-
result = (this.deltaPitch * rotationSpeed);
|
|
77
|
-
this.deltaPitch = 0;
|
|
78
|
-
break;
|
|
79
|
-
case DeltaYawField:
|
|
80
|
-
result = (this.deltaYaw * rotationSpeed);
|
|
81
|
-
this.deltaYaw = 0;
|
|
82
|
-
break;
|
|
83
|
-
case DeltaZoomField:
|
|
84
|
-
result = (this.deltaZoom * zoomSpeed);
|
|
85
|
-
this.deltaZoom = 0;
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
return result;
|
|
89
|
-
}
|
|
90
71
|
dispose() {
|
|
91
72
|
this.abortController.abort();
|
|
92
73
|
}
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import { Input, InputField } from './index.js';
|
|
2
|
-
export type PointerLockInputOptions = {
|
|
3
|
-
pointerLockRotationSpeed?: number;
|
|
4
|
-
pointerLockZoomSpeed?: number;
|
|
5
|
-
};
|
|
6
1
|
/**
|
|
7
2
|
* @requires to manually execute `domElement.requestPointerLock()`
|
|
8
3
|
*/
|
|
9
|
-
export declare class PointerLockInput
|
|
4
|
+
export declare class PointerLockInput {
|
|
10
5
|
private readonly abortController;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
options: {
|
|
7
|
+
rotationSpeed?: number;
|
|
8
|
+
zoomSpeed?: number;
|
|
9
|
+
};
|
|
14
10
|
constructor(domElement: HTMLElement);
|
|
15
|
-
get<T>(field: InputField<T>, options: PointerLockInputOptions): T | undefined;
|
|
16
11
|
dispose(): void;
|
|
17
12
|
}
|
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RotatePitchAction, RotateYawAction, ZoomAction } from './index.js';
|
|
2
2
|
/**
|
|
3
3
|
* @requires to manually execute `domElement.requestPointerLock()`
|
|
4
4
|
*/
|
|
5
5
|
export class PointerLockInput {
|
|
6
6
|
abortController = new AbortController();
|
|
7
|
-
|
|
8
|
-
deltaYaw = 0;
|
|
9
|
-
deltaPitch = 0;
|
|
7
|
+
options = {};
|
|
10
8
|
constructor(domElement) {
|
|
11
9
|
domElement.addEventListener('pointermove', (event) => {
|
|
12
10
|
if (document.pointerLockElement != domElement) {
|
|
13
11
|
return;
|
|
14
12
|
}
|
|
15
|
-
// Compute based on domElement bounds instead of window.innerHeight
|
|
16
13
|
const rect = domElement.getBoundingClientRect();
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
const rotationSpeed = this.options.rotationSpeed ?? 0.4;
|
|
15
|
+
RotateYawAction.write(-(event.movementX / rect.height) * rotationSpeed);
|
|
16
|
+
RotatePitchAction.write(-(event.movementY / rect.height) * rotationSpeed);
|
|
19
17
|
}, {
|
|
20
18
|
signal: this.abortController.signal,
|
|
21
19
|
});
|
|
@@ -23,32 +21,13 @@ export class PointerLockInput {
|
|
|
23
21
|
if (document.pointerLockElement != domElement) {
|
|
24
22
|
return;
|
|
25
23
|
}
|
|
26
|
-
this.
|
|
24
|
+
const zoomSpeed = this.options.zoomSpeed ?? 0.0001;
|
|
25
|
+
ZoomAction.write(event.deltaY * zoomSpeed);
|
|
27
26
|
event.preventDefault();
|
|
28
27
|
}, {
|
|
29
28
|
signal: this.abortController.signal,
|
|
30
29
|
});
|
|
31
30
|
}
|
|
32
|
-
get(field, options) {
|
|
33
|
-
const rotationSpeed = options.pointerLockRotationSpeed ?? 0.4;
|
|
34
|
-
const zoomSpeed = options.pointerLockZoomSpeed ?? 0.0001;
|
|
35
|
-
let result;
|
|
36
|
-
switch (field) {
|
|
37
|
-
case DeltaPitchField:
|
|
38
|
-
result = (this.deltaPitch * rotationSpeed);
|
|
39
|
-
this.deltaPitch = 0;
|
|
40
|
-
break;
|
|
41
|
-
case DeltaYawField:
|
|
42
|
-
result = (this.deltaYaw * rotationSpeed);
|
|
43
|
-
this.deltaYaw = 0;
|
|
44
|
-
break;
|
|
45
|
-
case DeltaZoomField:
|
|
46
|
-
result = (this.deltaZoom * zoomSpeed);
|
|
47
|
-
this.deltaZoom = 0;
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
52
31
|
dispose() {
|
|
53
32
|
this.abortController.abort();
|
|
54
33
|
}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import { Input, InputField } from './index.js';
|
|
2
1
|
export type ScreenJoystickInputOptions = {
|
|
3
2
|
screenJoystickRunDistancePx?: number;
|
|
4
3
|
screenJoystickDeadZonePx?: number;
|
|
5
4
|
};
|
|
6
|
-
export declare class ScreenJoystickInput
|
|
5
|
+
export declare class ScreenJoystickInput {
|
|
6
|
+
private readonly abortController;
|
|
7
7
|
readonly root: HTMLDivElement;
|
|
8
8
|
private readonly handle;
|
|
9
9
|
private pointerId;
|
|
10
|
-
private
|
|
11
|
-
private
|
|
12
|
-
private
|
|
10
|
+
private forwardWriter;
|
|
11
|
+
private backwardWriter;
|
|
12
|
+
private leftWriter;
|
|
13
|
+
private rightWriter;
|
|
14
|
+
private runWriter;
|
|
15
|
+
options: {
|
|
16
|
+
runDistancePx?: number;
|
|
17
|
+
deadZonePx?: number;
|
|
18
|
+
};
|
|
13
19
|
constructor(domElement: HTMLElement);
|
|
14
|
-
get<T>(field: InputField<T>, options: ScreenJoystickInputOptions): T | undefined;
|
|
15
20
|
dispose(): void;
|
|
16
21
|
private updateHandle;
|
|
17
22
|
private resetHandle;
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MoveForwardAction, MoveBackwardAction, MoveLeftAction, MoveRightAction, RunAction } from './index.js';
|
|
2
2
|
const DefaultDeadZonePx = 24;
|
|
3
3
|
const DefaultRunDistancePx = 46;
|
|
4
4
|
const JoystickRadius = 56;
|
|
5
5
|
export class ScreenJoystickInput {
|
|
6
|
+
abortController = new AbortController();
|
|
6
7
|
root;
|
|
7
8
|
handle;
|
|
8
9
|
pointerId;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
forwardWriter = MoveForwardAction.createWriter(this.abortController.signal);
|
|
11
|
+
backwardWriter = MoveBackwardAction.createWriter(this.abortController.signal);
|
|
12
|
+
leftWriter = MoveLeftAction.createWriter(this.abortController.signal);
|
|
13
|
+
rightWriter = MoveRightAction.createWriter(this.abortController.signal);
|
|
14
|
+
runWriter = RunAction.createWriter(this.abortController.signal);
|
|
15
|
+
options = {};
|
|
12
16
|
constructor(domElement) {
|
|
13
17
|
const parent = domElement.parentElement ?? domElement;
|
|
14
18
|
const joy = document.createElement('div');
|
|
@@ -78,43 +82,36 @@ export class ScreenJoystickInput {
|
|
|
78
82
|
e.preventDefault();
|
|
79
83
|
this.resetHandle();
|
|
80
84
|
};
|
|
81
|
-
joy.addEventListener('pointerdown', onPointerDown);
|
|
82
|
-
joy.addEventListener('pointermove', onPointerMove);
|
|
83
|
-
joy.addEventListener('pointerup', onPointerEnd);
|
|
84
|
-
joy.addEventListener('pointercancel', onPointerEnd);
|
|
85
|
-
}
|
|
86
|
-
get(field, options) {
|
|
87
|
-
switch (field) {
|
|
88
|
-
case MoveForwardField:
|
|
89
|
-
case MoveBackwardField:
|
|
90
|
-
const moveY = this.distanceToCenter <= (options.screenJoystickDeadZonePx ?? DefaultDeadZonePx)
|
|
91
|
-
? 0
|
|
92
|
-
: -this.clampedY / JoystickRadius;
|
|
93
|
-
return field === MoveForwardField ? Math.max(0, moveY) : Math.max(0, -moveY);
|
|
94
|
-
case MoveLeftField:
|
|
95
|
-
case MoveRightField:
|
|
96
|
-
const moveX = this.distanceToCenter <= (options.screenJoystickDeadZonePx ?? DefaultDeadZonePx)
|
|
97
|
-
? 0
|
|
98
|
-
: this.clampedX / JoystickRadius;
|
|
99
|
-
return field === MoveLeftField ? Math.max(0, moveX) : Math.max(0, moveX);
|
|
100
|
-
case RunField:
|
|
101
|
-
return (this.distanceToCenter > (options.screenJoystickRunDistancePx ?? DefaultRunDistancePx));
|
|
102
|
-
}
|
|
103
|
-
return undefined;
|
|
85
|
+
joy.addEventListener('pointerdown', onPointerDown, { signal: this.abortController.signal });
|
|
86
|
+
joy.addEventListener('pointermove', onPointerMove, { signal: this.abortController.signal });
|
|
87
|
+
joy.addEventListener('pointerup', onPointerEnd, { signal: this.abortController.signal });
|
|
88
|
+
joy.addEventListener('pointercancel', onPointerEnd, { signal: this.abortController.signal });
|
|
104
89
|
}
|
|
105
90
|
dispose() {
|
|
91
|
+
this.abortController.abort();
|
|
106
92
|
this.root.remove();
|
|
107
93
|
}
|
|
108
94
|
updateHandle(dx, dy) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
this.handle.style.transform = `translate(-50%,-50%) translate(${
|
|
95
|
+
const distanceToCenter = Math.hypot(dx, dy) || 1;
|
|
96
|
+
const clampedX = (dx / distanceToCenter) * Math.min(distanceToCenter, JoystickRadius);
|
|
97
|
+
const clampedY = (dy / distanceToCenter) * Math.min(distanceToCenter, JoystickRadius);
|
|
98
|
+
this.handle.style.transform = `translate(-50%,-50%) translate(${clampedX}px, ${clampedY}px)`;
|
|
99
|
+
const deadZone = this.options.deadZonePx ?? DefaultDeadZonePx;
|
|
100
|
+
const runDistance = this.options.runDistancePx ?? DefaultRunDistancePx;
|
|
101
|
+
const moveY = distanceToCenter <= deadZone ? 0 : -clampedY / JoystickRadius;
|
|
102
|
+
const moveX = distanceToCenter <= deadZone ? 0 : clampedX / JoystickRadius;
|
|
103
|
+
this.forwardWriter.write(Math.max(0, moveY));
|
|
104
|
+
this.backwardWriter.write(Math.max(0, -moveY));
|
|
105
|
+
this.leftWriter.write(Math.max(0, -moveX));
|
|
106
|
+
this.rightWriter.write(Math.max(0, moveX));
|
|
107
|
+
this.runWriter.write(distanceToCenter > runDistance);
|
|
113
108
|
}
|
|
114
109
|
resetHandle() {
|
|
115
110
|
this.handle.style.transform = 'translate(-50%,-50%)';
|
|
116
|
-
this.
|
|
117
|
-
this.
|
|
118
|
-
this.
|
|
111
|
+
this.forwardWriter.write(0);
|
|
112
|
+
this.backwardWriter.write(0);
|
|
113
|
+
this.leftWriter.write(0);
|
|
114
|
+
this.rightWriter.write(0);
|
|
115
|
+
this.runWriter.write(false);
|
|
119
116
|
}
|
|
120
117
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare class ScreenJumpButtonInput {
|
|
2
|
+
private readonly abortController;
|
|
3
3
|
readonly root: HTMLDivElement;
|
|
4
|
-
private lastJumpTime;
|
|
5
4
|
constructor(domElement: HTMLElement);
|
|
6
|
-
get<T>(field: InputField<T>): T | undefined;
|
|
7
5
|
dispose(): void;
|
|
8
6
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JumpAction } from './index.js';
|
|
2
2
|
export class ScreenJumpButtonInput {
|
|
3
|
+
abortController = new AbortController();
|
|
3
4
|
root;
|
|
4
|
-
lastJumpTime = null;
|
|
5
5
|
constructor(domElement) {
|
|
6
6
|
const parent = domElement.parentElement ?? domElement;
|
|
7
7
|
const btn = document.createElement('div');
|
|
@@ -27,23 +27,18 @@ export class ScreenJumpButtonInput {
|
|
|
27
27
|
const onPress = (e) => {
|
|
28
28
|
e.preventDefault();
|
|
29
29
|
e.stopPropagation();
|
|
30
|
-
|
|
30
|
+
JumpAction.emit();
|
|
31
31
|
};
|
|
32
32
|
const stopPropagation = (e) => {
|
|
33
33
|
e.stopPropagation();
|
|
34
34
|
e.preventDefault();
|
|
35
35
|
};
|
|
36
|
-
this.root.addEventListener('pointerdown', onPress);
|
|
37
|
-
this.root.addEventListener('pointermove', stopPropagation);
|
|
38
|
-
this.root.addEventListener('pointerup', stopPropagation);
|
|
39
|
-
}
|
|
40
|
-
get(field) {
|
|
41
|
-
if (field === LastTimeJumpPressedField) {
|
|
42
|
-
return this.lastJumpTime;
|
|
43
|
-
}
|
|
44
|
-
return undefined;
|
|
36
|
+
this.root.addEventListener('pointerdown', onPress, { signal: this.abortController.signal });
|
|
37
|
+
this.root.addEventListener('pointermove', stopPropagation, { signal: this.abortController.signal });
|
|
38
|
+
this.root.addEventListener('pointerup', stopPropagation, { signal: this.abortController.signal });
|
|
45
39
|
}
|
|
46
40
|
dispose() {
|
|
41
|
+
this.abortController.abort();
|
|
47
42
|
this.root.remove();
|
|
48
43
|
}
|
|
49
44
|
}
|