@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.
Files changed (48) hide show
  1. package/dist/animation/bone-map.d.ts +4 -0
  2. package/dist/animation/bone-map.js +11 -0
  3. package/dist/animation/default.d.ts +9 -1
  4. package/dist/animation/default.js +16 -9
  5. package/dist/animation/index.d.ts +8 -13
  6. package/dist/animation/index.js +61 -39
  7. package/dist/animation/mask.d.ts +4 -1
  8. package/dist/animation/mask.js +50 -0
  9. package/dist/camera.d.ts +6 -2
  10. package/dist/camera.js +22 -7
  11. package/dist/input/action.d.ts +41 -0
  12. package/dist/input/action.js +97 -0
  13. package/dist/input/index.d.ts +12 -26
  14. package/dist/input/index.js +17 -70
  15. package/dist/input/keyboard.d.ts +28 -5
  16. package/dist/input/keyboard.js +83 -69
  17. package/dist/input/pointer-capture.d.ts +5 -10
  18. package/dist/input/pointer-capture.js +9 -28
  19. package/dist/input/pointer-lock.d.ts +5 -10
  20. package/dist/input/pointer-lock.js +7 -28
  21. package/dist/input/screen-joystick.d.ts +11 -6
  22. package/dist/input/screen-joystick.js +31 -34
  23. package/dist/input/screen-jump-button.d.ts +2 -4
  24. package/dist/input/screen-jump-button.js +7 -12
  25. package/dist/model/index.d.ts +1 -2
  26. package/dist/simple-character/apply-input-options.d.ts +2 -0
  27. package/dist/simple-character/apply-input-options.js +28 -0
  28. package/dist/simple-character/index.d.ts +21 -6
  29. package/dist/simple-character/index.js +12 -17
  30. package/dist/simple-character/state/jump-down.js +2 -1
  31. package/dist/simple-character/state/jump-forward.js +4 -2
  32. package/dist/simple-character/state/jump-loop.js +2 -1
  33. package/dist/simple-character/state/jump-start.js +2 -2
  34. package/dist/simple-character/state/jump-up.js +4 -2
  35. package/dist/simple-character/state/movement.js +12 -8
  36. package/dist/simple-character/update-input-velocity.d.ts +1 -2
  37. package/dist/simple-character/update-input-velocity.js +4 -4
  38. package/dist/utils.d.ts +5 -5
  39. package/dist/utils.js +15 -6
  40. package/package.json +2 -2
  41. package/dist/animation/bvh.d.ts +0 -4
  42. package/dist/animation/bvh.js +0 -8
  43. package/dist/animation/fbx.d.ts +0 -4
  44. package/dist/animation/fbx.js +0 -8
  45. package/dist/animation/gltf.d.ts +0 -3
  46. package/dist/animation/gltf.js +0 -8
  47. package/dist/animation/vrma.d.ts +0 -3
  48. package/dist/animation/vrma.js +0 -8
@@ -1,5 +1,4 @@
1
1
  import { AnimationAction, AnimationMixer, Object3D, Quaternion } from 'three';
2
- import { CharacterAnimationMask } from '../animation/index.js';
3
2
  export { VRMHumanBoneName } from '@pixiv/three-vrm';
4
3
  export * from './vrm.js';
5
4
  export type CharacterModelOptions = {
@@ -23,7 +22,7 @@ export declare function flattenCharacterModelOptions(options: Exclude<CharacterM
23
22
  export type CharacterModel = {
24
23
  mixer: AnimationMixer;
25
24
  scene: Object3D;
26
- currentAnimations: Map<CharacterAnimationMask | undefined, AnimationAction>;
25
+ currentAnimations: Map<string | undefined, AnimationAction>;
27
26
  boneRotationOffset?: Quaternion;
28
27
  };
29
28
  export declare function loadCharacterModel(url?: string, type?: Exclude<CharacterModelOptions, boolean>['type'], boneRotationOffset?: Quaternion, castShadow?: boolean, receiveShadow?: boolean): Promise<CharacterModel>;
@@ -0,0 +1,2 @@
1
+ import { SimpleCharacterInputOptions } from './index.js';
2
+ export declare function applySimpleCharacterInputOptions(inputs: Array<unknown>, options?: SimpleCharacterInputOptions): void;
@@ -0,0 +1,28 @@
1
+ import { DefaultJumpKeys, DefaultMoveBackwardKeys, DefaultMoveForwardKeys, DefaultMoveLeftKeys, DefaultMoveRightKeys, DefaultRunKeys, LocomotionKeyboardInput, } from '../input/keyboard.js';
2
+ import { PointerCaptureInput } from '../input/pointer-capture.js';
3
+ import { PointerLockInput } from '../input/pointer-lock.js';
4
+ import { ScreenJoystickInput } from '../input/screen-joystick.js';
5
+ export function applySimpleCharacterInputOptions(inputs, options) {
6
+ for (const input of inputs) {
7
+ if (input instanceof ScreenJoystickInput) {
8
+ input.options.deadZonePx = options?.screenJoystickDeadZonePx;
9
+ input.options.runDistancePx = options?.screenJoystickRunDistancePx;
10
+ }
11
+ if (input instanceof PointerCaptureInput) {
12
+ input.options.rotationSpeed = options?.pointerCaptureRotationSpeed;
13
+ input.options.zoomSpeed = options?.pointerCaptureZoomSpeed;
14
+ }
15
+ if (input instanceof PointerLockInput) {
16
+ input.options.rotationSpeed = options?.pointerLockRotationSpeed;
17
+ input.options.zoomSpeed = options?.pointerLockZoomSpeed;
18
+ }
19
+ if (input instanceof LocomotionKeyboardInput) {
20
+ input.forward.options.keys = options?.keyboardMoveForwardKeys ?? DefaultMoveForwardKeys;
21
+ input.backward.options.keys = options?.keyboardMoveBackwardKeys ?? DefaultMoveBackwardKeys;
22
+ input.left.options.keys = options?.keyboardMoveLeftKeys ?? DefaultMoveLeftKeys;
23
+ input.right.options.keys = options?.keyboardMoveRightKeys ?? DefaultMoveRightKeys;
24
+ input.run.options.keys = options?.keyboardRunKeys ?? DefaultRunKeys;
25
+ input.jump.options.keys = options?.keyboardJumpKeys ?? DefaultJumpKeys;
26
+ }
27
+ }
28
+ }
@@ -1,14 +1,12 @@
1
1
  import { Group, Object3D, Object3DEventMap, AnimationAction } from 'three';
2
2
  import { CharacterAnimationOptions } from '../animation/index.js';
3
3
  import { CharacterCameraBehavior, SimpleCharacterCameraBehaviorOptions } from '../camera.js';
4
- import { Input, ScreenJoystickInputOptions, LocomotionKeyboardInputOptions, PointerCaptureInputOptions, PointerLockInputOptions, InputSystem } from '../input/index.js';
5
4
  import { CharacterModelOptions, CharacterModel } from '../model/index.js';
6
5
  import { BvhCharacterPhysicsOptions, BvhCharacterPhysics, BvhPhysicsWorld } from '../physics/index.js';
7
6
  export type SimpleCharacterState = {
8
7
  camera: Object3D;
9
8
  model?: CharacterModel;
10
9
  physics: BvhCharacterPhysics;
11
- inputSystem: InputSystem;
12
10
  lastJump: number;
13
11
  };
14
12
  export type SimpleCharacterMovementOptions = {
@@ -63,10 +61,25 @@ export type SimpleCharacterAnimationOptions = {
63
61
  */
64
62
  crossFadeDuration?: number;
65
63
  };
66
- export type SimpleCharacterInputOptions = ScreenJoystickInputOptions & PointerCaptureInputOptions & PointerLockInputOptions & LocomotionKeyboardInputOptions;
64
+ export type SimpleCharacterInputOptions = {
65
+ screenJoystickRunDistancePx?: number;
66
+ screenJoystickDeadZonePx?: number;
67
+ pointerCaptureRotationSpeed?: number;
68
+ pointerCaptureZoomSpeed?: number;
69
+ pointerLockRotationSpeed?: number;
70
+ pointerLockZoomSpeed?: number;
71
+ keyboardMoveForwardKeys?: Array<string>;
72
+ keyboardMoveBackwardKeys?: Array<string>;
73
+ keyboardMoveLeftKeys?: Array<string>;
74
+ keyboardMoveRightKeys?: Array<string>;
75
+ keyboardRunKeys?: Array<string>;
76
+ keyboardJumpKeys?: Array<string>;
77
+ };
67
78
  export type SimpleCharacterOptions = {
68
- readonly input?: ReadonlyArray<Input | {
69
- new (domElement: HTMLElement): Input;
79
+ readonly input?: ReadonlyArray<{
80
+ new (domElement: HTMLElement): {
81
+ dispose(): void;
82
+ };
70
83
  }>;
71
84
  inputOptions?: SimpleCharacterInputOptions;
72
85
  movement?: SimpleCharacterMovementOptions;
@@ -83,7 +96,6 @@ export declare class SimpleCharacter extends Group<Object3DEventMap & {
83
96
  private readonly options;
84
97
  readonly cameraBehavior: CharacterCameraBehavior;
85
98
  readonly physics: BvhCharacterPhysics;
86
- readonly inputSystem: InputSystem;
87
99
  readonly currentAnimationRef: {
88
100
  current?: AnimationAction;
89
101
  };
@@ -91,7 +103,9 @@ export declare class SimpleCharacter extends Group<Object3DEventMap & {
91
103
  private readonly updateTimeline;
92
104
  private readonly graph;
93
105
  private readonly abortController;
106
+ private readonly inputs;
94
107
  lastJump: number;
108
+ readonly abortSignal: AbortSignal;
95
109
  constructor(camera: Object3D, world: BvhPhysicsWorld, domElement: HTMLElement, options?: SimpleCharacterOptions);
96
110
  private init;
97
111
  update(delta: number): void;
@@ -99,3 +113,4 @@ export declare class SimpleCharacter extends Group<Object3DEventMap & {
99
113
  }
100
114
  export * from './update-input-velocity.js';
101
115
  export * from './update-rotation.js';
116
+ export * from './apply-input-options.js';
@@ -2,7 +2,7 @@ import { VRM, VRMUtils } from '@pixiv/three-vrm';
2
2
  import { runTimeline, GraphTimeline } from '@pmndrs/timeline';
3
3
  import { Group, Vector3 } from 'three';
4
4
  import { CharacterCameraBehavior } from '../camera.js';
5
- import { LocomotionKeyboardInput, PointerCaptureInput, ScreenJoystickInput, ScreenJumpButtonInput, InputSystem, } from '../input/index.js';
5
+ import { LocomotionKeyboardInput, PointerCaptureInput, ScreenJoystickInput, ScreenJumpButtonInput, } from '../input/index.js';
6
6
  import { loadCharacterModel, flattenCharacterModelOptions, } from '../model/index.js';
7
7
  import { BvhCharacterPhysics } from '../physics/index.js';
8
8
  import { loadSimpleCharacterJumpDownState } from './state/jump-down.js';
@@ -14,38 +14,31 @@ import { loadSimpleCharacterMovingState } from './state/movement.js';
14
14
  import { updateSimpleCharacterInputVelocity } from './update-input-velocity.js';
15
15
  import { updateSimpleCharacterRotation } from './update-rotation.js';
16
16
  import { shouldJump } from '../utils.js';
17
+ import { applySimpleCharacterInputOptions } from './apply-input-options.js';
17
18
  export class SimpleCharacter extends Group {
18
19
  camera;
19
20
  world;
20
21
  options;
21
22
  cameraBehavior;
22
23
  physics;
23
- inputSystem;
24
24
  currentAnimationRef = {};
25
25
  //loaded asychronously
26
26
  model;
27
27
  updateTimeline;
28
28
  graph = new GraphTimeline('moving');
29
29
  abortController = new AbortController();
30
+ inputs;
30
31
  lastJump = 0;
32
+ abortSignal = this.abortController.signal;
31
33
  constructor(camera, world, domElement, options = {}) {
32
34
  super();
33
35
  this.camera = camera;
34
36
  this.world = world;
35
37
  this.options = options;
36
- this.inputSystem = new InputSystem();
37
- const inputOptions = options.input ?? [
38
- ScreenJoystickInput,
39
- ScreenJumpButtonInput,
40
- PointerCaptureInput,
41
- LocomotionKeyboardInput,
42
- ];
43
- for (let input of inputOptions) {
44
- this.inputSystem.add(typeof input === 'function' ? new input(domElement) : input);
45
- }
38
+ this.inputs = (options.input ?? [ScreenJoystickInput, ScreenJumpButtonInput, PointerCaptureInput, LocomotionKeyboardInput]).map((Input) => new Input(domElement));
39
+ applySimpleCharacterInputOptions(this.inputs, options.inputOptions);
46
40
  // camera behavior
47
41
  this.cameraBehavior = new CharacterCameraBehavior();
48
- console.log(this.graph);
49
42
  // physics
50
43
  this.physics = new BvhCharacterPhysics(world);
51
44
  // timeline graph
@@ -81,29 +74,31 @@ export class SimpleCharacter extends Group {
81
74
  const jumpOptions = this.options.movement?.jump;
82
75
  if (jumpOptions != false &&
83
76
  this.model == null &&
84
- shouldJump(this.physics, this.inputSystem, this.lastJump, jumpOptions == true ? undefined : jumpOptions?.bufferTime)) {
77
+ shouldJump(this.physics, this.lastJump, jumpOptions == true ? undefined : jumpOptions?.bufferTime)) {
85
78
  this.physics.applyVelocity(new Vector3(0, (typeof this.options.movement?.jump === 'object' ? this.options.movement?.jump.speed : undefined) ?? 8, 0));
86
79
  this.lastJump = performance.now() / 1000;
87
80
  }
88
81
  if (this.model != null) {
89
82
  updateSimpleCharacterRotation(delta, this.physics, this.camera, this.model, this.options.animation);
90
83
  }
91
- updateSimpleCharacterInputVelocity(this.camera, this.inputSystem, this.physics, this.options.movement);
84
+ updateSimpleCharacterInputVelocity(this.camera, this.physics, this.options.movement);
92
85
  this.updateTimeline?.(undefined, delta);
93
86
  this.model?.mixer.update(delta);
94
87
  if (this.model instanceof VRM) {
95
88
  this.model.update(delta);
96
89
  }
97
90
  this.physics.update(this, delta, this.options.physics);
98
- this.cameraBehavior.update(this.camera, this, this.inputSystem, delta, this.world.raycast.bind(this.world), this.options.cameraBehavior);
91
+ this.cameraBehavior.update(this.camera, this, delta, this.world.raycast.bind(this.world), this.options.cameraBehavior);
99
92
  }
100
93
  dispose() {
101
94
  this.abortController.abort();
102
95
  this.parent?.remove(this);
103
96
  this.model?.scene.dispatchEvent({ type: 'dispose' });
104
- this.inputSystem.dispose();
97
+ this.inputs.forEach((input) => input.dispose());
98
+ this.cameraBehavior.dispose();
105
99
  VRMUtils.deepDispose(this);
106
100
  }
107
101
  }
108
102
  export * from './update-input-velocity.js';
109
103
  export * from './update-rotation.js';
104
+ export * from './apply-input-options.js';
@@ -1,5 +1,6 @@
1
1
  import { action, timePassed } from '@pmndrs/timeline';
2
2
  import { LoopOnce } from 'three';
3
+ import { JumpDownAnimationUrl } from '../../animation/default.js';
3
4
  import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
4
5
  import { startAnimation } from '../../utils.js';
5
6
  import { DefaultCrossFadeDuration } from '../defaults.js';
@@ -8,7 +9,7 @@ export async function loadSimpleCharacterJumpDownState(state, options) {
8
9
  if (model == null) {
9
10
  throw new Error(`Unable to load animation without existing model`);
10
11
  }
11
- const jumpDown = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(options.animation?.jumpDown ?? { url: { default: 'jumpDown' } })));
12
+ const jumpDown = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({ url: JumpDownAnimationUrl, ...options.animation?.jumpDown })));
12
13
  jumpDown.loop = LoopOnce;
13
14
  jumpDown.clampWhenFinished = true;
14
15
  return {
@@ -1,5 +1,6 @@
1
1
  import { action, animationFinished } from '@pmndrs/timeline';
2
2
  import { LoopOnce, Vector3 } from 'three';
3
+ import { JumpForwardAnimationUrl } from '../../animation/default.js';
3
4
  import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
4
5
  import { startAnimation } from '../../utils.js';
5
6
  import { DefaultCrossFadeDuration } from '../defaults.js';
@@ -8,9 +9,10 @@ export async function loadSimpleCharacterJumpForwardAction(state, options) {
8
9
  if (model == null) {
9
10
  throw new Error(`Unable to load animation without existing model`);
10
11
  }
11
- const jumpForward = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(options.animation?.jumpForward ?? {
12
- url: { default: 'jumpForward' },
12
+ const jumpForward = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
13
+ url: JumpForwardAnimationUrl,
13
14
  scaleTime: 0.9,
15
+ ...options.animation?.jumpForward,
14
16
  })));
15
17
  jumpForward.loop = LoopOnce;
16
18
  jumpForward.clampWhenFinished = true;
@@ -1,4 +1,5 @@
1
1
  import { action } from '@pmndrs/timeline';
2
+ import { JumpLoopAnimationUrl } from '../../animation/default.js';
2
3
  import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
3
4
  import { startAnimation } from '../../utils.js';
4
5
  import { DefaultCrossFadeDuration } from '../defaults.js';
@@ -7,7 +8,7 @@ export async function loadSimpleCharacterJumpLoopState(state, options) {
7
8
  if (model == null) {
8
9
  throw new Error(`Unable to load animation without existing model`);
9
10
  }
10
- const jumpLoop = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(options.animation?.jumpLoop ?? { url: { default: 'jumpLoop' } })));
11
+ const jumpLoop = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({ url: JumpLoopAnimationUrl, ...options.animation?.jumpLoop })));
11
12
  return {
12
13
  timeline: () => action({
13
14
  init: () => {
@@ -1,5 +1,5 @@
1
1
  import { action, timePassed } from '@pmndrs/timeline';
2
- import { RunField } from '../../input/index.js';
2
+ import { RunAction } from '../../input/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) {
@@ -24,7 +24,7 @@ export async function loadSimpleCharacterJumpStartState(jumpUp, jumpForward, sta
24
24
  }),
25
25
  transitionTo: {
26
26
  jumpDown: { whenUpdate: () => !state.physics.isGrounded },
27
- finally: () => (state.inputSystem.get(RunField) ? 'jumpForward' : 'jumpUp'),
27
+ finally: () => (RunAction.get() ? 'jumpForward' : 'jumpUp'),
28
28
  },
29
29
  };
30
30
  }
@@ -1,5 +1,6 @@
1
1
  import { action, animationFinished } from '@pmndrs/timeline';
2
2
  import { LoopOnce, Vector3 } from 'three';
3
+ import { JumpUpAnimationUrl } from '../../animation/default.js';
3
4
  import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
4
5
  import { startAnimation } from '../../utils.js';
5
6
  export async function loadSimpleCharacterJumpUpAction(state, options) {
@@ -7,8 +8,9 @@ export async function loadSimpleCharacterJumpUpAction(state, options) {
7
8
  if (model == null) {
8
9
  throw new Error(`Unable to load animation without existing model`);
9
10
  }
10
- const jumpUp = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(options.animation?.jumpUp ?? {
11
- url: { default: 'jumpUp' },
11
+ const jumpUp = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
12
+ url: JumpUpAnimationUrl,
13
+ ...options.animation?.jumpUp,
12
14
  })));
13
15
  jumpUp.loop = LoopOnce;
14
16
  jumpUp.clampWhenFinished = true;
@@ -1,6 +1,7 @@
1
1
  import { action } from '@pmndrs/timeline';
2
+ import { IdleAnimationUrl, RunAnimationUrl, WalkAnimationUrl } from '../../animation/default.js';
2
3
  import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
3
- import { RunField } from '../../input/index.js';
4
+ import { RunAction } from '../../input/index.js';
4
5
  import { shouldJump, startAnimation } from '../../utils.js';
5
6
  import { DefaultCrossFadeDuration } from '../defaults.js';
6
7
  export async function loadSimpleCharacterMovingState(state, options) {
@@ -8,16 +9,19 @@ export async function loadSimpleCharacterMovingState(state, options) {
8
9
  if (model == null) {
9
10
  throw new Error(`Unable to load animation without existing model`);
10
11
  }
11
- const idle = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(options.animation?.idle ?? {
12
- url: { default: 'idle' },
12
+ const idle = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
13
+ url: IdleAnimationUrl,
14
+ ...options.animation?.idle,
13
15
  })));
14
16
  const run = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
15
- url: { default: 'run' },
17
+ url: RunAnimationUrl,
16
18
  scaleTime: 0.8,
19
+ ...options.animation?.run,
17
20
  })));
18
- const walk = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(options.animation?.walk ?? {
21
+ const walk = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
19
22
  scaleTime: 0.5,
20
- url: { default: 'walk' },
23
+ url: WalkAnimationUrl,
24
+ ...options.animation?.walk,
21
25
  })));
22
26
  return {
23
27
  timeline: () => {
@@ -28,7 +32,7 @@ export async function loadSimpleCharacterMovingState(state, options) {
28
32
  if (state.physics.inputVelocity.lengthSq() === 0) {
29
33
  nextAnimation = idle;
30
34
  }
31
- else if (state.inputSystem.get(RunField) && options.movement?.run != false) {
35
+ else if (RunAction.get() && options.movement?.run != false) {
32
36
  nextAnimation = run;
33
37
  }
34
38
  else if (options.movement?.walk != false) {
@@ -51,7 +55,7 @@ export async function loadSimpleCharacterMovingState(state, options) {
51
55
  transitionTo: {
52
56
  jumpStart: {
53
57
  whenUpdate: () => options.movement?.jump !== false &&
54
- shouldJump(state.physics, state.inputSystem, state.lastJump, options.movement?.jump === true ? undefined : options.movement?.jump?.bufferTime),
58
+ shouldJump(state.physics, state.lastJump, options.movement?.jump === true ? undefined : options.movement?.jump?.bufferTime),
55
59
  },
56
60
  jumpLoop: { whenUpdate: () => !state.physics.isGrounded },
57
61
  },
@@ -1,5 +1,4 @@
1
1
  import { Object3D } from 'three';
2
- import { InputSystem } from '../input/index.js';
3
2
  import type { SimpleCharacterMovementOptions } from './index.js';
4
3
  import type { BvhCharacterPhysics } from '../physics/index.js';
5
- export declare function updateSimpleCharacterInputVelocity(camera: Object3D, inputSystem: InputSystem, physics: BvhCharacterPhysics, options?: SimpleCharacterMovementOptions): void;
4
+ export declare function updateSimpleCharacterInputVelocity(camera: Object3D, physics: BvhCharacterPhysics, options?: SimpleCharacterMovementOptions): void;
@@ -1,14 +1,14 @@
1
1
  import { Euler, Quaternion } from 'three';
2
- import { RunField, MoveLeftField, MoveRightField, MoveForwardField, MoveBackwardField, } from '../input/index.js';
2
+ import { RunAction, MoveLeftAction, MoveRightAction, MoveForwardAction, MoveBackwardAction } from '../input/index.js';
3
3
  const cameraEuler = new Euler();
4
4
  const cameraRotation = new Quaternion();
5
- export function updateSimpleCharacterInputVelocity(camera, inputSystem, physics, options) {
5
+ export function updateSimpleCharacterInputVelocity(camera, physics, options) {
6
6
  cameraEuler.setFromQuaternion(camera.getWorldQuaternion(cameraRotation), 'YXZ');
7
7
  cameraEuler.x = 0;
8
8
  cameraEuler.z = 0;
9
9
  let inputSpeed = 0;
10
10
  let runOptions = options?.run ?? true;
11
- if (inputSystem.get(RunField) && runOptions !== false) {
11
+ if (RunAction.get() && runOptions !== false) {
12
12
  runOptions = runOptions === true ? {} : runOptions;
13
13
  inputSpeed = runOptions.speed ?? 6;
14
14
  }
@@ -18,7 +18,7 @@ export function updateSimpleCharacterInputVelocity(camera, inputSystem, physics,
18
18
  inputSpeed = walkOptions.speed ?? 3;
19
19
  }
20
20
  physics.inputVelocity
21
- .set(-inputSystem.get(MoveLeftField) + inputSystem.get(MoveRightField), 0, -inputSystem.get(MoveForwardField) + inputSystem.get(MoveBackwardField))
21
+ .set(-MoveLeftAction.get() + MoveRightAction.get(), 0, -MoveForwardAction.get() + MoveBackwardAction.get())
22
22
  .normalize()
23
23
  .applyEuler(cameraEuler)
24
24
  .multiplyScalar(inputSpeed);
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { type InputSystem } from './input/index.js';
2
- import type { CharacterAnimationMask } from './animation/index.js';
3
1
  import type { CharacterModel } from './model/index.js';
4
2
  import type { BvhCharacterPhysics } from './physics/index.js';
5
3
  import type { AnimationAction } from 'three';
@@ -7,8 +5,10 @@ export declare function getIsMobileMediaQuery(): MediaQueryList | undefined;
7
5
  export declare function isMobile(): boolean;
8
6
  export type StartAnimationOptions = {
9
7
  fadeDuration?: number;
8
+ sync?: boolean;
10
9
  paused?: boolean;
11
- mask?: CharacterAnimationMask;
10
+ crossFade?: boolean;
11
+ layer?: string;
12
12
  };
13
- export declare function startAnimation(animation: AnimationAction, currentAnimations: CharacterModel['currentAnimations'], { fadeDuration, paused, mask }: StartAnimationOptions): void;
14
- export declare function shouldJump(physics: BvhCharacterPhysics, inputSystem: InputSystem, lastJump: number, bufferTime?: number): boolean;
13
+ export declare function startAnimation(animation: AnimationAction, currentAnimations: CharacterModel['currentAnimations'], { crossFade, layer, fadeDuration, paused, sync }: StartAnimationOptions): (() => void) | undefined;
14
+ export declare function shouldJump(physics: BvhCharacterPhysics, lastJump: number, bufferTime?: number): boolean;
package/dist/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- import { LastTimeJumpPressedField } from './input/index.js';
1
+ import { JumpAction } from './input/index.js';
2
2
  export function getIsMobileMediaQuery() {
3
3
  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
4
4
  return undefined;
@@ -8,24 +8,33 @@ export function getIsMobileMediaQuery() {
8
8
  export function isMobile() {
9
9
  return getIsMobileMediaQuery()?.matches ?? false;
10
10
  }
11
- export function startAnimation(animation, currentAnimations, { fadeDuration = 0.1, paused = false, mask }) {
11
+ export function startAnimation(animation, currentAnimations, { crossFade = true, layer, fadeDuration = 0.1, paused = false, sync = false }) {
12
12
  animation.reset();
13
13
  animation.play();
14
14
  animation.paused = paused;
15
- const currentAnimation = currentAnimations.get(mask);
15
+ if (!crossFade) {
16
+ animation.fadeIn(fadeDuration);
17
+ return () => {
18
+ animation.fadeOut(fadeDuration);
19
+ };
20
+ }
21
+ const currentAnimation = currentAnimations.get(layer);
22
+ if (currentAnimation != null && sync) {
23
+ animation.syncWith(currentAnimation);
24
+ }
16
25
  if (currentAnimation != null) {
17
26
  animation.crossFadeFrom(currentAnimation, fadeDuration);
18
27
  }
19
28
  else {
20
29
  animation.fadeIn(fadeDuration);
21
30
  }
22
- currentAnimations.set(mask, animation);
31
+ currentAnimations.set(layer, animation);
23
32
  }
24
- export function shouldJump(physics, inputSystem, lastJump, bufferTime = 0.1) {
33
+ export function shouldJump(physics, lastJump, bufferTime = 0.1) {
25
34
  if (!physics.isGrounded) {
26
35
  return false;
27
36
  }
28
- const lastTimePressed = inputSystem.get(LastTimeJumpPressedField);
37
+ const lastTimePressed = JumpAction.getLatestTime();
29
38
  if (lastTimePressed == null || lastJump > lastTimePressed) {
30
39
  return false;
31
40
  }
package/package.json CHANGED
@@ -21,12 +21,12 @@
21
21
  "peerDependencies": {
22
22
  "three": "*"
23
23
  },
24
- "version": "0.2.0",
24
+ "version": "0.2.1",
25
25
  "type": "module",
26
26
  "dependencies": {
27
27
  "@pixiv/three-vrm": "^3.4.2",
28
28
  "@pixiv/three-vrm-animation": "^3.4.2",
29
- "@pmndrs/timeline": "^0.3.5",
29
+ "@pmndrs/timeline": "^0.3.7",
30
30
  "@viverse/sdk": "1.2.10-alpha.0",
31
31
  "three-mesh-bvh": "^0.9.1"
32
32
  },
@@ -1,4 +0,0 @@
1
- import { AnimationClip } from 'three';
2
- import type { CharacterModel } from '../model/index.js';
3
- import type { VRMHumanBoneName } from '@pixiv/three-vrm';
4
- export declare function loadVrmModelBvhAnimations(model: CharacterModel, url: string, removeXZMovement: boolean, boneMap?: Record<string, VRMHumanBoneName>): Promise<Array<AnimationClip>>;
@@ -1,8 +0,0 @@
1
- import { BVHLoader } from 'three/examples/jsm/Addons.js';
2
- import { bvhBoneMap, fixModelAnimationClip } from './index.js';
3
- const loader = new BVHLoader();
4
- export async function loadVrmModelBvhAnimations(model, url, removeXZMovement, boneMap) {
5
- const clipScene = await loader.loadAsync(url);
6
- fixModelAnimationClip(model, clipScene.clip, undefined, removeXZMovement, boneMap ?? bvhBoneMap);
7
- return [clipScene.clip];
8
- }
@@ -1,4 +0,0 @@
1
- import { AnimationClip } from 'three';
2
- import type { CharacterModel } from '../model/index.js';
3
- import type { VRMHumanBoneName } from '@pixiv/three-vrm';
4
- export declare function loadVrmModelFbxAnimations(model: CharacterModel, url: string, removeXZMovement: boolean, boneMap?: Record<string, VRMHumanBoneName>): Promise<Array<AnimationClip>>;
@@ -1,8 +0,0 @@
1
- import { FBXLoader } from 'three/examples/jsm/Addons.js';
2
- import { fixModelAnimationClip } from './index.js';
3
- const loader = new FBXLoader();
4
- export async function loadVrmModelFbxAnimations(model, url, removeXZMovement, boneMap) {
5
- const clipScene = await loader.loadAsync(url);
6
- clipScene.animations.forEach((clip) => fixModelAnimationClip(model, clip, clipScene, removeXZMovement, boneMap));
7
- return clipScene.animations;
8
- }
@@ -1,3 +0,0 @@
1
- import { AnimationClip } from 'three';
2
- import type { CharacterModel, VRMHumanBoneName } from '../model/index.js';
3
- export declare function loadVrmModelGltfAnimations(model: CharacterModel, url: string, removeXZMovement: boolean, boneMap?: Record<string, VRMHumanBoneName>): Promise<Array<AnimationClip>>;
@@ -1,8 +0,0 @@
1
- import { GLTFLoader } from 'three/examples/jsm/Addons.js';
2
- import { fixModelAnimationClip } from './index.js';
3
- const loader = new GLTFLoader();
4
- export async function loadVrmModelGltfAnimations(model, url, removeXZMovement, boneMap) {
5
- const { animations, scene: clipScene } = await loader.loadAsync(url);
6
- animations.forEach((clip) => fixModelAnimationClip(model, clip, clipScene, removeXZMovement, boneMap));
7
- return animations;
8
- }
@@ -1,3 +0,0 @@
1
- import { VRM } from '@pixiv/three-vrm';
2
- import { AnimationClip } from 'three';
3
- export declare function loadVrmModelVrmaAnimations(vrm: VRM, url: string, removeXZMovement: boolean): Promise<Array<AnimationClip>>;
@@ -1,8 +0,0 @@
1
- import { createVRMAnimationClip } from '@pixiv/three-vrm-animation';
2
- import { vrmaLoader } from '../index.js';
3
- export async function loadVrmModelVrmaAnimations(vrm, url, removeXZMovement) {
4
- const animations = await vrmaLoader.loadAsync(url);
5
- const vrmAnimations = animations.userData.vrmAnimations;
6
- const clips = vrmAnimations.map((vrmAnimation) => createVRMAnimationClip(vrmAnimation, vrm));
7
- return clips;
8
- }