@pmndrs/viverse 0.2.1 → 0.2.2
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/{input → action}/action.d.ts +19 -20
- package/dist/{input → action}/action.js +56 -39
- package/dist/{input → action}/index.d.ts +6 -5
- package/dist/{input → action}/index.js +5 -4
- package/dist/action/keyboard.d.ts +26 -0
- package/dist/action/keyboard.js +89 -0
- package/dist/action/pointer-capture.d.ts +8 -0
- package/dist/{input → action}/pointer-capture.js +16 -22
- package/dist/action/pointer-lock.d.ts +6 -0
- package/dist/action/pointer-lock.js +49 -0
- package/dist/action/pointer.d.ts +18 -0
- package/dist/action/pointer.js +90 -0
- package/dist/action/screen-joystick.d.ts +16 -0
- package/dist/{input → action}/screen-joystick.js +36 -33
- package/dist/action/screen-jump-button.d.ts +6 -0
- package/dist/action/screen-jump-button.js +32 -0
- package/dist/camera.d.ts +3 -3
- package/dist/camera.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/simple-character/apply-input-options.d.ts +2 -2
- package/dist/simple-character/apply-input-options.js +28 -22
- package/dist/simple-character/index.d.ts +17 -9
- package/dist/simple-character/index.js +13 -9
- package/dist/simple-character/state/jump-start.js +1 -1
- package/dist/simple-character/state/movement.js +1 -1
- package/dist/simple-character/update-input-velocity.d.ts +1 -1
- package/dist/simple-character/update-input-velocity.js +2 -2
- package/dist/simple-character/update-rotation.js +1 -1
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/dist/input/keyboard.d.ts +0 -39
- package/dist/input/keyboard.js +0 -96
- package/dist/input/pointer-capture.d.ts +0 -15
- package/dist/input/pointer-lock.d.ts +0 -12
- package/dist/input/pointer-lock.js +0 -34
- package/dist/input/screen-joystick.d.ts +0 -23
- package/dist/input/screen-jump-button.d.ts +0 -6
- package/dist/input/screen-jump-button.js +0 -44
|
@@ -1,24 +1,29 @@
|
|
|
1
|
-
import { MoveForwardAction, MoveBackwardAction, MoveLeftAction, MoveRightAction, RunAction } from './index.js';
|
|
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
|
-
export class
|
|
6
|
-
|
|
5
|
+
export class ScreenJoystickLocomotionActionBindings {
|
|
6
|
+
abortSignal;
|
|
7
7
|
root;
|
|
8
8
|
handle;
|
|
9
9
|
pointerId;
|
|
10
|
-
forwardWriter
|
|
11
|
-
backwardWriter
|
|
12
|
-
leftWriter
|
|
13
|
-
rightWriter
|
|
14
|
-
runWriter
|
|
15
|
-
options
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.
|
|
10
|
+
forwardWriter;
|
|
11
|
+
backwardWriter;
|
|
12
|
+
leftWriter;
|
|
13
|
+
rightWriter;
|
|
14
|
+
runWriter;
|
|
15
|
+
//options
|
|
16
|
+
runDistancePx;
|
|
17
|
+
deadZonePx;
|
|
18
|
+
constructor(domElement, abortSignal) {
|
|
19
|
+
this.abortSignal = abortSignal;
|
|
20
|
+
this.forwardWriter = MoveForwardAction.createWriter(this.abortSignal);
|
|
21
|
+
this.backwardWriter = MoveBackwardAction.createWriter(this.abortSignal);
|
|
22
|
+
this.leftWriter = MoveLeftAction.createWriter(this.abortSignal);
|
|
23
|
+
this.rightWriter = MoveRightAction.createWriter(this.abortSignal);
|
|
24
|
+
this.runWriter = RunAction.createWriter(this.abortSignal);
|
|
25
|
+
this.root = document.createElement('div');
|
|
26
|
+
this.root.className = 'viverse-joystick mobile-only';
|
|
22
27
|
this.root.style.position = 'absolute';
|
|
23
28
|
this.root.style.bottom = '24px';
|
|
24
29
|
this.root.style.left = '24px';
|
|
@@ -31,10 +36,12 @@ export class ScreenJoystickInput {
|
|
|
31
36
|
this.root.style.userSelect = 'none';
|
|
32
37
|
this.root.style.setProperty('-webkit-user-select', 'none');
|
|
33
38
|
this.root.style.setProperty('-webkit-touch-callout', 'none');
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
this.handle =
|
|
39
|
+
const parent = domElement.parentElement ?? domElement;
|
|
40
|
+
parent.appendChild(this.root);
|
|
41
|
+
this.abortSignal.addEventListener('abort', () => this.root.remove(), { once: true });
|
|
42
|
+
this.handle = document.createElement('div');
|
|
43
|
+
this.handle.className = 'viverse-joystick-handle';
|
|
44
|
+
this.root.appendChild(this.handle);
|
|
38
45
|
this.handle.style.position = 'absolute';
|
|
39
46
|
this.handle.style.left = '50%';
|
|
40
47
|
this.handle.style.top = '50%';
|
|
@@ -55,9 +62,9 @@ export class ScreenJoystickInput {
|
|
|
55
62
|
}
|
|
56
63
|
e.preventDefault();
|
|
57
64
|
e.stopPropagation();
|
|
58
|
-
|
|
65
|
+
this.root.setPointerCapture(e.pointerId);
|
|
59
66
|
this.pointerId = e.pointerId;
|
|
60
|
-
const rect =
|
|
67
|
+
const rect = this.root.getBoundingClientRect();
|
|
61
68
|
const joyCenterX = rect.left + rect.width / 2;
|
|
62
69
|
const joyCenterY = rect.top + rect.height / 2;
|
|
63
70
|
this.updateHandle(e.clientX - joyCenterX, e.clientY - joyCenterY);
|
|
@@ -68,7 +75,7 @@ export class ScreenJoystickInput {
|
|
|
68
75
|
}
|
|
69
76
|
e.preventDefault();
|
|
70
77
|
e.stopPropagation();
|
|
71
|
-
const rect =
|
|
78
|
+
const rect = this.root.getBoundingClientRect();
|
|
72
79
|
const joyCenterX = rect.left + rect.width / 2;
|
|
73
80
|
const joyCenterY = rect.top + rect.height / 2;
|
|
74
81
|
this.updateHandle(e.clientX - joyCenterX, e.clientY - joyCenterY);
|
|
@@ -78,26 +85,22 @@ export class ScreenJoystickInput {
|
|
|
78
85
|
return;
|
|
79
86
|
}
|
|
80
87
|
this.pointerId = undefined;
|
|
81
|
-
|
|
88
|
+
this.root.releasePointerCapture(e.pointerId);
|
|
82
89
|
e.preventDefault();
|
|
83
90
|
this.resetHandle();
|
|
84
91
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
dispose() {
|
|
91
|
-
this.abortController.abort();
|
|
92
|
-
this.root.remove();
|
|
92
|
+
this.root.addEventListener('pointerdown', onPointerDown, { signal: this.abortSignal });
|
|
93
|
+
this.root.addEventListener('pointermove', onPointerMove, { signal: this.abortSignal });
|
|
94
|
+
this.root.addEventListener('pointerup', onPointerEnd, { signal: this.abortSignal });
|
|
95
|
+
this.root.addEventListener('pointercancel', onPointerEnd, { signal: this.abortSignal });
|
|
93
96
|
}
|
|
94
97
|
updateHandle(dx, dy) {
|
|
95
98
|
const distanceToCenter = Math.hypot(dx, dy) || 1;
|
|
96
99
|
const clampedX = (dx / distanceToCenter) * Math.min(distanceToCenter, JoystickRadius);
|
|
97
100
|
const clampedY = (dy / distanceToCenter) * Math.min(distanceToCenter, JoystickRadius);
|
|
98
101
|
this.handle.style.transform = `translate(-50%,-50%) translate(${clampedX}px, ${clampedY}px)`;
|
|
99
|
-
const deadZone = this.
|
|
100
|
-
const runDistance = this.
|
|
102
|
+
const deadZone = this.deadZonePx ?? DefaultDeadZonePx;
|
|
103
|
+
const runDistance = this.runDistancePx ?? DefaultRunDistancePx;
|
|
101
104
|
const moveY = distanceToCenter <= deadZone ? 0 : -clampedY / JoystickRadius;
|
|
102
105
|
const moveX = distanceToCenter <= deadZone ? 0 : clampedX / JoystickRadius;
|
|
103
106
|
this.forwardWriter.write(Math.max(0, moveY));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const defaultScreenButtonStyles: Partial<CSSStyleDeclaration>;
|
|
2
|
+
export declare const jumpButtonImage = "url(\"data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2024%2024%22%20fill=%22none%22%20stroke=%22%23444%22%20stroke-width=%222%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%3E%3Cpolyline%20points=%2218%2015%2012%209%206%2015%22/%3E%3C/svg%3E\")";
|
|
3
|
+
export declare class ScreenButtonJumpActionBindings {
|
|
4
|
+
readonly root: HTMLDivElement;
|
|
5
|
+
constructor(domElement: HTMLElement, abortSignal: AbortSignal);
|
|
6
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { JumpAction } from './index.js';
|
|
2
|
+
import { PointerButtonActionBinding } from './pointer.js';
|
|
3
|
+
export const defaultScreenButtonStyles = {
|
|
4
|
+
position: 'absolute',
|
|
5
|
+
bottom: '32px',
|
|
6
|
+
right: '126px',
|
|
7
|
+
minWidth: '64px',
|
|
8
|
+
height: '64px',
|
|
9
|
+
borderRadius: '9999px',
|
|
10
|
+
pointerEvents: 'auto',
|
|
11
|
+
touchAction: 'none',
|
|
12
|
+
userSelect: 'none',
|
|
13
|
+
background: 'rgba(255,255,255,0.3)',
|
|
14
|
+
backgroundRepeat: 'no-repeat',
|
|
15
|
+
backgroundPosition: 'center',
|
|
16
|
+
backgroundSize: '50%',
|
|
17
|
+
};
|
|
18
|
+
Object.assign(defaultScreenButtonStyles, { '-webkit-user-select': 'none' });
|
|
19
|
+
export const jumpButtonImage = 'url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2024%2024%22%20fill=%22none%22%20stroke=%22%23444%22%20stroke-width=%222%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%3E%3Cpolyline%20points=%2218%2015%2012%209%206%2015%22/%3E%3C/svg%3E")';
|
|
20
|
+
export class ScreenButtonJumpActionBindings {
|
|
21
|
+
root;
|
|
22
|
+
constructor(domElement, abortSignal) {
|
|
23
|
+
const parent = domElement.parentElement ?? domElement;
|
|
24
|
+
this.root = document.createElement('div');
|
|
25
|
+
this.root.className = 'viverse-button viverse-jump mobile-only';
|
|
26
|
+
parent.appendChild(this.root);
|
|
27
|
+
abortSignal.addEventListener('abort', () => this.root.remove(), { once: true });
|
|
28
|
+
Object.assign(this.root.style, defaultScreenButtonStyles);
|
|
29
|
+
new PointerButtonActionBinding(JumpAction, this.root, abortSignal);
|
|
30
|
+
this.root.addEventListener('pointerdown', (e) => e.stopPropagation(), { signal: abortSignal });
|
|
31
|
+
}
|
|
32
|
+
}
|
package/dist/camera.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Object3D, Vector3, Vector3Tuple, Ray } from 'three';
|
|
2
|
-
export declare const FirstPersonCharacterCameraBehavior:
|
|
3
|
-
export type
|
|
2
|
+
export declare const FirstPersonCharacterCameraBehavior: CharacterCameraBehaviorOptions;
|
|
3
|
+
export type CharacterCameraBehaviorOptions = {
|
|
4
4
|
/**
|
|
5
5
|
* @default true
|
|
6
6
|
*/
|
|
@@ -73,6 +73,6 @@ export declare class CharacterCameraBehavior {
|
|
|
73
73
|
/**
|
|
74
74
|
* @param delta in seconds
|
|
75
75
|
*/
|
|
76
|
-
update(camera: Object3D, target: Object3D, deltaTime: number, raycast?: (ray: Ray, far: number) => number | undefined, options?:
|
|
76
|
+
update(camera: Object3D, target: Object3D, deltaTime: number, raycast?: (ray: Ray, far: number) => number | undefined, options?: CharacterCameraBehaviorOptions): void;
|
|
77
77
|
dispose(): void;
|
|
78
78
|
}
|
package/dist/camera.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Vector3, Euler, Ray, Quaternion } from 'three';
|
|
2
2
|
import { clamp } from 'three/src/math/MathUtils.js';
|
|
3
|
-
import { RotatePitchAction, RotateYawAction, ZoomAction } from './
|
|
3
|
+
import { RotatePitchAction, RotateYawAction, ZoomAction } from './action/index.js';
|
|
4
4
|
export const FirstPersonCharacterCameraBehavior = {
|
|
5
5
|
characterBaseOffset: [0, 1.6, 0],
|
|
6
6
|
zoom: { maxDistance: 0, minDistance: 0 },
|
|
@@ -77,7 +77,7 @@ export class CharacterCameraBehavior {
|
|
|
77
77
|
characterWorldPosition.add(chracterBaseOffsetHelper);
|
|
78
78
|
camera.getWorldPosition(deltaHelper);
|
|
79
79
|
deltaHelper.sub(characterWorldPosition);
|
|
80
|
-
// apply rotation
|
|
80
|
+
// apply rotation actions to rotationYaw and rotationPitch if not disabled or first update
|
|
81
81
|
let rotationOptions = options.rotation ?? true;
|
|
82
82
|
if (!this.firstUpdate && rotationOptions !== false) {
|
|
83
83
|
rotationOptions = rotationOptions === true ? {} : rotationOptions;
|
|
@@ -96,7 +96,7 @@ export class CharacterCameraBehavior {
|
|
|
96
96
|
camera.rotation.set(this.rotationPitch, this.rotationYaw, 0, 'YXZ');
|
|
97
97
|
rayHelper.direction.set(0, 0, 1).applyEuler(camera.rotation);
|
|
98
98
|
rayHelper.origin.copy(characterWorldPosition);
|
|
99
|
-
// apply zoom
|
|
99
|
+
// apply zoom action to zoomDistance if not disabled or first update
|
|
100
100
|
let zoomOptions = options.zoom ?? true;
|
|
101
101
|
if (!this.firstUpdate && zoomOptions !== false) {
|
|
102
102
|
zoomOptions = zoomOptions === true ? {} : zoomOptions;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function
|
|
1
|
+
import { SimpleCharacterActionBindingOptions } from './index.js';
|
|
2
|
+
export declare function applySimpleCharacterActionBindingOptions(actionBindingsList: Array<unknown>, options?: SimpleCharacterActionBindingOptions): void;
|
|
@@ -1,28 +1,34 @@
|
|
|
1
|
-
import { DefaultJumpKeys, DefaultMoveBackwardKeys, DefaultMoveForwardKeys, DefaultMoveLeftKeys, DefaultMoveRightKeys, DefaultRunKeys,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
export function
|
|
6
|
-
for (const
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { DefaultJumpKeys, DefaultMoveBackwardKeys, DefaultMoveForwardKeys, DefaultMoveLeftKeys, DefaultMoveRightKeys, DefaultRunKeys, KeyboardLocomotionActionBindings, } from '../action/keyboard.js';
|
|
2
|
+
import { PointerCaptureRotateZoomActionBindings } from '../action/pointer-capture.js';
|
|
3
|
+
import { PointerLockRotateZoomActionBindings } from '../action/pointer-lock.js';
|
|
4
|
+
import { ScreenJoystickLocomotionActionBindings } from '../action/screen-joystick.js';
|
|
5
|
+
export function applySimpleCharacterActionBindingOptions(actionBindingsList, options) {
|
|
6
|
+
for (const actionBindings of actionBindingsList) {
|
|
7
|
+
if (actionBindings instanceof ScreenJoystickLocomotionActionBindings) {
|
|
8
|
+
actionBindings.deadZonePx = options?.screenJoystickDeadZonePx;
|
|
9
|
+
actionBindings.runDistancePx = options?.screenJoystickRunDistancePx;
|
|
10
10
|
}
|
|
11
|
-
if (
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
if (actionBindings instanceof PointerCaptureRotateZoomActionBindings) {
|
|
12
|
+
actionBindings.rotationSpeed = options?.pointerCaptureRotationSpeed;
|
|
13
|
+
actionBindings.zoomSpeed = options?.pointerCaptureZoomSpeed;
|
|
14
14
|
}
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
if (actionBindings instanceof PointerLockRotateZoomActionBindings) {
|
|
16
|
+
actionBindings.rotationSpeed = options?.pointerLockRotationSpeed;
|
|
17
|
+
actionBindings.zoomSpeed = options?.pointerLockZoomSpeed;
|
|
18
18
|
}
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
if (actionBindings instanceof KeyboardLocomotionActionBindings) {
|
|
20
|
+
actionBindings.moveForwardBinding.keys = options?.keyboardMoveForwardKeys ?? DefaultMoveForwardKeys;
|
|
21
|
+
actionBindings.moveBackwardBinding.requiresPointerLock = options?.keyboardRequiresPointerLock;
|
|
22
|
+
actionBindings.moveBackwardBinding.keys = options?.keyboardMoveBackwardKeys ?? DefaultMoveBackwardKeys;
|
|
23
|
+
actionBindings.moveBackwardBinding.requiresPointerLock = options?.keyboardRequiresPointerLock;
|
|
24
|
+
actionBindings.moveLeftBinding.keys = options?.keyboardMoveLeftKeys ?? DefaultMoveLeftKeys;
|
|
25
|
+
actionBindings.moveLeftBinding.requiresPointerLock = options?.keyboardRequiresPointerLock;
|
|
26
|
+
actionBindings.moveRightBinding.keys = options?.keyboardMoveRightKeys ?? DefaultMoveRightKeys;
|
|
27
|
+
actionBindings.moveRightBinding.requiresPointerLock = options?.keyboardRequiresPointerLock;
|
|
28
|
+
actionBindings.runBinding.keys = options?.keyboardRunKeys ?? DefaultRunKeys;
|
|
29
|
+
actionBindings.runBinding.requiresPointerLock = options?.keyboardRequiresPointerLock;
|
|
30
|
+
actionBindings.jumpBinding.keys = options?.keyboardJumpKeys ?? DefaultJumpKeys;
|
|
31
|
+
actionBindings.jumpBinding.requiresPointerLock = options?.keyboardRequiresPointerLock;
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
34
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Group, Object3D, Object3DEventMap, AnimationAction } from 'three';
|
|
2
2
|
import { CharacterAnimationOptions } from '../animation/index.js';
|
|
3
|
-
import { CharacterCameraBehavior,
|
|
3
|
+
import { CharacterCameraBehavior, CharacterCameraBehaviorOptions } from '../camera.js';
|
|
4
4
|
import { CharacterModelOptions, CharacterModel } from '../model/index.js';
|
|
5
5
|
import { BvhCharacterPhysicsOptions, BvhCharacterPhysics, BvhPhysicsWorld } from '../physics/index.js';
|
|
6
6
|
export type SimpleCharacterState = {
|
|
@@ -51,7 +51,7 @@ export type SimpleCharacterAnimationOptions = {
|
|
|
51
51
|
/**
|
|
52
52
|
* @default "movement"
|
|
53
53
|
*/
|
|
54
|
-
|
|
54
|
+
yawRotationBasedOn?: 'camera' | 'movement';
|
|
55
55
|
/**
|
|
56
56
|
* @default 10
|
|
57
57
|
*/
|
|
@@ -61,13 +61,14 @@ export type SimpleCharacterAnimationOptions = {
|
|
|
61
61
|
*/
|
|
62
62
|
crossFadeDuration?: number;
|
|
63
63
|
};
|
|
64
|
-
export type
|
|
64
|
+
export type SimpleCharacterActionBindingOptions = {
|
|
65
65
|
screenJoystickRunDistancePx?: number;
|
|
66
66
|
screenJoystickDeadZonePx?: number;
|
|
67
67
|
pointerCaptureRotationSpeed?: number;
|
|
68
68
|
pointerCaptureZoomSpeed?: number;
|
|
69
69
|
pointerLockRotationSpeed?: number;
|
|
70
70
|
pointerLockZoomSpeed?: number;
|
|
71
|
+
keyboardRequiresPointerLock?: boolean;
|
|
71
72
|
keyboardMoveForwardKeys?: Array<string>;
|
|
72
73
|
keyboardMoveBackwardKeys?: Array<string>;
|
|
73
74
|
keyboardMoveLeftKeys?: Array<string>;
|
|
@@ -76,16 +77,24 @@ export type SimpleCharacterInputOptions = {
|
|
|
76
77
|
keyboardJumpKeys?: Array<string>;
|
|
77
78
|
};
|
|
78
79
|
export type SimpleCharacterOptions = {
|
|
80
|
+
/**
|
|
81
|
+
* @deprecated use actionBindings instead
|
|
82
|
+
*/
|
|
79
83
|
readonly input?: ReadonlyArray<{
|
|
80
|
-
new (domElement: HTMLElement):
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
new (domElement: HTMLElement, abortSignal: AbortSignal): any;
|
|
85
|
+
}>;
|
|
86
|
+
readonly actionBindings?: ReadonlyArray<{
|
|
87
|
+
new (domElement: HTMLElement, abortSignal: AbortSignal): any;
|
|
83
88
|
}>;
|
|
84
|
-
|
|
89
|
+
/**
|
|
90
|
+
* @deprecated use actionBindingOptions instead
|
|
91
|
+
*/
|
|
92
|
+
inputOptions?: SimpleCharacterActionBindingOptions;
|
|
93
|
+
actionBindingOptions?: SimpleCharacterActionBindingOptions;
|
|
85
94
|
movement?: SimpleCharacterMovementOptions;
|
|
86
95
|
readonly model?: CharacterModelOptions | boolean;
|
|
87
96
|
physics?: BvhCharacterPhysicsOptions;
|
|
88
|
-
cameraBehavior?:
|
|
97
|
+
cameraBehavior?: CharacterCameraBehaviorOptions;
|
|
89
98
|
readonly animation?: SimpleCharacterAnimationOptions;
|
|
90
99
|
};
|
|
91
100
|
export declare class SimpleCharacter extends Group<Object3DEventMap & {
|
|
@@ -103,7 +112,6 @@ export declare class SimpleCharacter extends Group<Object3DEventMap & {
|
|
|
103
112
|
private readonly updateTimeline;
|
|
104
113
|
private readonly graph;
|
|
105
114
|
private readonly abortController;
|
|
106
|
-
private readonly inputs;
|
|
107
115
|
lastJump: number;
|
|
108
116
|
readonly abortSignal: AbortSignal;
|
|
109
117
|
constructor(camera: Object3D, world: BvhPhysicsWorld, domElement: HTMLElement, options?: SimpleCharacterOptions);
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { VRM, VRMUtils } from '@pixiv/three-vrm';
|
|
2
2
|
import { runTimeline, GraphTimeline } from '@pmndrs/timeline';
|
|
3
3
|
import { Group, Vector3 } from 'three';
|
|
4
|
+
import { applySimpleCharacterActionBindingOptions } from './apply-input-options.js';
|
|
5
|
+
import { KeyboardLocomotionActionBindings, PointerCaptureRotateZoomActionBindings, ScreenJoystickLocomotionActionBindings, ScreenButtonJumpActionBindings, } from '../action/index.js';
|
|
4
6
|
import { CharacterCameraBehavior } from '../camera.js';
|
|
5
|
-
import { LocomotionKeyboardInput, PointerCaptureInput, ScreenJoystickInput, ScreenJumpButtonInput, } from '../input/index.js';
|
|
6
7
|
import { loadCharacterModel, flattenCharacterModelOptions, } from '../model/index.js';
|
|
7
8
|
import { BvhCharacterPhysics } from '../physics/index.js';
|
|
9
|
+
import { shouldJump } from '../utils.js';
|
|
8
10
|
import { loadSimpleCharacterJumpDownState } from './state/jump-down.js';
|
|
9
11
|
import { loadSimpleCharacterJumpForwardAction, loadSimpleCharacterJumpForwardState } from './state/jump-forward.js';
|
|
10
12
|
import { loadSimpleCharacterJumpLoopState } from './state/jump-loop.js';
|
|
11
13
|
import { loadSimpleCharacterJumpStartState } from './state/jump-start.js';
|
|
12
14
|
import { loadSimpleCharacterJumpUpAction, loadSimpleCharacterJumpUpState } from './state/jump-up.js';
|
|
13
15
|
import { loadSimpleCharacterMovingState } from './state/movement.js';
|
|
14
|
-
import {
|
|
16
|
+
import { updateSimpleCharacterVelocity } from './update-input-velocity.js';
|
|
15
17
|
import { updateSimpleCharacterRotation } from './update-rotation.js';
|
|
16
|
-
import { shouldJump } from '../utils.js';
|
|
17
|
-
import { applySimpleCharacterInputOptions } from './apply-input-options.js';
|
|
18
18
|
export class SimpleCharacter extends Group {
|
|
19
19
|
camera;
|
|
20
20
|
world;
|
|
@@ -27,7 +27,6 @@ export class SimpleCharacter extends Group {
|
|
|
27
27
|
updateTimeline;
|
|
28
28
|
graph = new GraphTimeline('moving');
|
|
29
29
|
abortController = new AbortController();
|
|
30
|
-
inputs;
|
|
31
30
|
lastJump = 0;
|
|
32
31
|
abortSignal = this.abortController.signal;
|
|
33
32
|
constructor(camera, world, domElement, options = {}) {
|
|
@@ -35,8 +34,14 @@ export class SimpleCharacter extends Group {
|
|
|
35
34
|
this.camera = camera;
|
|
36
35
|
this.world = world;
|
|
37
36
|
this.options = options;
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const actionBindingsList = (options.actionBindings ??
|
|
38
|
+
options.input ?? [
|
|
39
|
+
ScreenJoystickLocomotionActionBindings,
|
|
40
|
+
ScreenButtonJumpActionBindings,
|
|
41
|
+
PointerCaptureRotateZoomActionBindings,
|
|
42
|
+
KeyboardLocomotionActionBindings,
|
|
43
|
+
]).map((ActionBindings) => new ActionBindings(domElement, this.abortController.signal));
|
|
44
|
+
applySimpleCharacterActionBindingOptions(actionBindingsList, options.actionBindingOptions ?? options.inputOptions);
|
|
40
45
|
// camera behavior
|
|
41
46
|
this.cameraBehavior = new CharacterCameraBehavior();
|
|
42
47
|
// physics
|
|
@@ -81,7 +86,7 @@ export class SimpleCharacter extends Group {
|
|
|
81
86
|
if (this.model != null) {
|
|
82
87
|
updateSimpleCharacterRotation(delta, this.physics, this.camera, this.model, this.options.animation);
|
|
83
88
|
}
|
|
84
|
-
|
|
89
|
+
updateSimpleCharacterVelocity(this.camera, this.physics, this.options.movement);
|
|
85
90
|
this.updateTimeline?.(undefined, delta);
|
|
86
91
|
this.model?.mixer.update(delta);
|
|
87
92
|
if (this.model instanceof VRM) {
|
|
@@ -94,7 +99,6 @@ export class SimpleCharacter extends Group {
|
|
|
94
99
|
this.abortController.abort();
|
|
95
100
|
this.parent?.remove(this);
|
|
96
101
|
this.model?.scene.dispatchEvent({ type: 'dispose' });
|
|
97
|
-
this.inputs.forEach((input) => input.dispose());
|
|
98
102
|
this.cameraBehavior.dispose();
|
|
99
103
|
VRMUtils.deepDispose(this);
|
|
100
104
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { action, timePassed } from '@pmndrs/timeline';
|
|
2
|
-
import { RunAction } from '../../
|
|
2
|
+
import { RunAction } from '../../action/index.js';
|
|
3
3
|
import { startAnimation } from '../../utils.js';
|
|
4
4
|
import { DefaultCrossFadeDuration, DefaultJumDelay } from '../defaults.js';
|
|
5
5
|
export async function loadSimpleCharacterJumpStartState(jumpUp, jumpForward, state, options) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { action } from '@pmndrs/timeline';
|
|
2
|
+
import { RunAction } from '../../action/index.js';
|
|
2
3
|
import { IdleAnimationUrl, RunAnimationUrl, WalkAnimationUrl } from '../../animation/default.js';
|
|
3
4
|
import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
|
|
4
|
-
import { RunAction } from '../../input/index.js';
|
|
5
5
|
import { shouldJump, startAnimation } from '../../utils.js';
|
|
6
6
|
import { DefaultCrossFadeDuration } from '../defaults.js';
|
|
7
7
|
export async function loadSimpleCharacterMovingState(state, options) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Object3D } from 'three';
|
|
2
2
|
import type { SimpleCharacterMovementOptions } from './index.js';
|
|
3
3
|
import type { BvhCharacterPhysics } from '../physics/index.js';
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function updateSimpleCharacterVelocity(camera: Object3D, physics: BvhCharacterPhysics, options?: SimpleCharacterMovementOptions): void;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Euler, Quaternion } from 'three';
|
|
2
|
-
import { RunAction, MoveLeftAction, MoveRightAction, MoveForwardAction, MoveBackwardAction } from '../
|
|
2
|
+
import { RunAction, MoveLeftAction, MoveRightAction, MoveForwardAction, MoveBackwardAction } from '../action/index.js';
|
|
3
3
|
const cameraEuler = new Euler();
|
|
4
4
|
const cameraRotation = new Quaternion();
|
|
5
|
-
export function
|
|
5
|
+
export function updateSimpleCharacterVelocity(camera, physics, options) {
|
|
6
6
|
cameraEuler.setFromQuaternion(camera.getWorldQuaternion(cameraRotation), 'YXZ');
|
|
7
7
|
cameraEuler.x = 0;
|
|
8
8
|
cameraEuler.z = 0;
|
|
@@ -7,7 +7,7 @@ const inputDirection = new Vector3();
|
|
|
7
7
|
const quaternion = new Quaternion();
|
|
8
8
|
export function updateSimpleCharacterRotation(delta, physics, camera, model, options) {
|
|
9
9
|
// Character yaw rotation logic
|
|
10
|
-
const basedOn = options?.
|
|
10
|
+
const basedOn = options?.yawRotationBasedOn ?? 'movement';
|
|
11
11
|
// compute goalTargetEuler
|
|
12
12
|
if (basedOn === 'camera') {
|
|
13
13
|
goalTargetEuler.setFromQuaternion(camera.getWorldQuaternion(quaternion), 'YXZ');
|
package/dist/utils.js
CHANGED
package/package.json
CHANGED
package/dist/input/keyboard.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
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
|
-
}
|
|
16
|
-
export type LocomotionKeyboardInputOptions = {
|
|
17
|
-
keyboardMoveForwardKeys?: Array<string>;
|
|
18
|
-
keyboardMoveBackwardKeys?: Array<string>;
|
|
19
|
-
keyboardMoveLeftKeys?: Array<string>;
|
|
20
|
-
keyboardMoveRightKeys?: Array<string>;
|
|
21
|
-
keyboardRunKeys?: Array<string>;
|
|
22
|
-
keyboardJumpKeys?: Array<string>;
|
|
23
|
-
};
|
|
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;
|
|
37
|
-
constructor(domElement: HTMLElement);
|
|
38
|
-
dispose(): void;
|
|
39
|
-
}
|
package/dist/input/keyboard.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { JumpAction, MoveBackwardAction, MoveForwardAction, MoveLeftAction, MoveRightAction, RunAction, } from './index.js';
|
|
2
|
-
export class KeyboardInput {
|
|
3
|
-
domElement;
|
|
4
|
-
abortController = new AbortController();
|
|
5
|
-
options = {};
|
|
6
|
-
abortSignal = this.abortController.signal;
|
|
7
|
-
pressedKeys = new Set();
|
|
8
|
-
constructor(domElement) {
|
|
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;
|
|
35
|
-
}
|
|
36
|
-
const wasEmpty = this.pressedKeys.size === 0;
|
|
37
|
-
this.pressedKeys.add(e.code);
|
|
38
|
-
if (wasEmpty && this.pressedKeys.size > 0) {
|
|
39
|
-
write(true);
|
|
40
|
-
}
|
|
41
|
-
}, { signal: this.abortController.signal });
|
|
42
|
-
this.domElement.addEventListener('keyup', (e) => {
|
|
43
|
-
if (!isWatched(e)) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (this.pressedKeys.delete(e.code) && this.pressedKeys.size === 0) {
|
|
47
|
-
write(false);
|
|
48
|
-
}
|
|
49
|
-
}, { signal: this.abortController.signal });
|
|
50
|
-
// Handle focus loss to clear pressed keys
|
|
51
|
-
this.domElement.addEventListener('blur', () => {
|
|
52
|
-
if (this.pressedKeys.size > 0) {
|
|
53
|
-
this.pressedKeys.clear();
|
|
54
|
-
write(false);
|
|
55
|
-
}
|
|
56
|
-
}, { signal: this.abortController.signal });
|
|
57
|
-
}
|
|
58
|
-
dispose() {
|
|
59
|
-
this.abortController.abort();
|
|
60
|
-
}
|
|
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,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @requires to manually execute `domElement.setPointerCapture(pointerId)` on pointerdown
|
|
3
|
-
*/
|
|
4
|
-
export declare class PointerCaptureInput {
|
|
5
|
-
private readonly domElement;
|
|
6
|
-
private readonly abortController;
|
|
7
|
-
private activePointers;
|
|
8
|
-
private lastPinchDist;
|
|
9
|
-
options: {
|
|
10
|
-
rotationSpeed?: number;
|
|
11
|
-
zoomSpeed?: number;
|
|
12
|
-
};
|
|
13
|
-
constructor(domElement: HTMLElement);
|
|
14
|
-
dispose(): void;
|
|
15
|
-
}
|