@react-three/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.d.ts +21 -3
- package/dist/animation.js +33 -7
- package/dist/bone.d.ts +4 -0
- package/dist/bone.js +4 -0
- package/dist/gamepad.d.ts +1 -2
- package/dist/gamepad.js +22 -33
- package/dist/simple.js +16 -15
- package/dist/utils.d.ts +10 -5
- package/dist/utils.js +34 -22
- package/package.json +3 -3
package/dist/animation.d.ts
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
import { CharacterAnimationOptions, StartAnimationOptions } from '@pmndrs/viverse';
|
|
2
2
|
import { RootState } from '@react-three/fiber';
|
|
3
3
|
import { ActionParams } from '@react-three/timeline';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
import { AnimationAction, AnimationActionLoopStyles, AnimationClip } from 'three';
|
|
6
|
+
export type AdditiveCharacterAnimationActionProps = Omit<CharacterAnimationActionProps, 'additiveToClip'> & {
|
|
7
|
+
referenceClip: CharacterAnimationOptions;
|
|
8
|
+
};
|
|
9
|
+
export declare const AdditiveCharacterAnimationAction: import("react").ForwardRefExoticComponent<Omit<CharacterAnimationActionProps, "additiveToClip"> & {
|
|
10
|
+
referenceClip: CharacterAnimationOptions;
|
|
11
|
+
} & import("react").RefAttributes<AnimationAction>>;
|
|
12
|
+
export type CharacterAnimationActionProps = {
|
|
6
13
|
dependencies?: Array<unknown>;
|
|
7
14
|
until?: () => Promise<unknown>;
|
|
8
15
|
loop?: AnimationActionLoopStyles;
|
|
9
|
-
|
|
16
|
+
additiveReferenceClip?: AnimationClip;
|
|
17
|
+
} & Omit<ActionParams<RootState>, 'until'> & CharacterAnimationOptions & StartAnimationOptions;
|
|
18
|
+
export declare function CharacterAnimationLayer({ name, children }: {
|
|
19
|
+
name: string;
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare const CharacterAnimationAction: import("react").ForwardRefExoticComponent<{
|
|
23
|
+
dependencies?: Array<unknown>;
|
|
24
|
+
until?: () => Promise<unknown>;
|
|
25
|
+
loop?: AnimationActionLoopStyles;
|
|
26
|
+
additiveReferenceClip?: AnimationClip;
|
|
27
|
+
} & Omit<ActionParams<RootState>, "until"> & CharacterAnimationOptions & StartAnimationOptions & import("react").RefAttributes<AnimationAction>>;
|
package/dist/animation.js
CHANGED
|
@@ -1,18 +1,44 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { startAnimation } from '@pmndrs/viverse';
|
|
3
3
|
import { Action, animationFinished } from '@react-three/timeline';
|
|
4
|
-
import { useMemo } from 'react';
|
|
4
|
+
import { createContext, forwardRef, useContext, useImperativeHandle, useMemo } from 'react';
|
|
5
5
|
import { LoopRepeat } from 'three';
|
|
6
|
+
import { makeClipAdditive } from 'three/src/animation/AnimationUtils.js';
|
|
6
7
|
import { useCharacterModel } from './model.js';
|
|
7
8
|
import { useCharacterAnimationLoader } from './utils.js';
|
|
8
|
-
export
|
|
9
|
+
export const AdditiveCharacterAnimationAction = forwardRef(({ referenceClip: referenceClipOptions, ...props }, ref) => {
|
|
9
10
|
const model = useCharacterModel();
|
|
10
|
-
const
|
|
11
|
+
const referenceClip = useCharacterAnimationLoader(model, { ...props, ...referenceClipOptions });
|
|
12
|
+
return _jsx(CharacterAnimationAction, { ref: ref, additiveReferenceClip: referenceClip, ...props });
|
|
13
|
+
});
|
|
14
|
+
const CharacterAnimationLayerContext = createContext(undefined);
|
|
15
|
+
export function CharacterAnimationLayer({ name, children }) {
|
|
16
|
+
return _jsx(CharacterAnimationLayerContext.Provider, { value: name, children: children });
|
|
17
|
+
}
|
|
18
|
+
export const CharacterAnimationAction = forwardRef(({ additiveReferenceClip, until, init, dependencies, update, fadeDuration, paused, loop, sync, crossFade, layer, ...animationOptions }, ref) => {
|
|
19
|
+
const layerFromContext = useContext(CharacterAnimationLayerContext);
|
|
20
|
+
layer ??= layerFromContext;
|
|
21
|
+
const model = useCharacterModel();
|
|
22
|
+
const srcClip = useCharacterAnimationLoader(model, animationOptions);
|
|
23
|
+
const clip = useMemo(() => additiveReferenceClip == null ? srcClip : makeClipAdditive(srcClip.clone(), undefined, additiveReferenceClip), [srcClip, additiveReferenceClip]);
|
|
11
24
|
const animation = useMemo(() => model.mixer.clipAction(clip), [clip, model]);
|
|
12
25
|
animation.clampWhenFinished = true;
|
|
13
26
|
animation.loop = loop ?? LoopRepeat;
|
|
27
|
+
useImperativeHandle(ref, () => animation, [animation]);
|
|
14
28
|
return (_jsx(Action, { init: () => {
|
|
15
|
-
startAnimation(animation, model.currentAnimations, {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
const cleanupAnimation = startAnimation(animation, model.currentAnimations, {
|
|
30
|
+
layer,
|
|
31
|
+
fadeDuration,
|
|
32
|
+
paused,
|
|
33
|
+
sync,
|
|
34
|
+
crossFade,
|
|
35
|
+
});
|
|
36
|
+
const cleanupInit = init?.();
|
|
37
|
+
return () => {
|
|
38
|
+
cleanupInit?.();
|
|
39
|
+
cleanupAnimation?.();
|
|
40
|
+
};
|
|
41
|
+
}, until: until ?? (() => animationFinished(animation)), update: update, dependencies: dependencies != null
|
|
42
|
+
? [...dependencies, animationOptions.mask, fadeDuration, paused, sync, crossFade, animation, model, layer]
|
|
43
|
+
: undefined }));
|
|
44
|
+
});
|
package/dist/bone.d.ts
CHANGED
|
@@ -4,3 +4,7 @@ export declare function CharacterModelBone({ bone, children }: {
|
|
|
4
4
|
bone: VRMHumanBoneName;
|
|
5
5
|
children?: ReactNode;
|
|
6
6
|
}): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated use CharacterModelBone instead
|
|
9
|
+
*/
|
|
10
|
+
export declare const VrmCharacterModelBone: typeof CharacterModelBone;
|
package/dist/bone.js
CHANGED
|
@@ -12,3 +12,7 @@ export function CharacterModelBone({ bone, children }) {
|
|
|
12
12
|
}
|
|
13
13
|
return (_jsx(Fragment, { children: createPortal(_jsx("group", { quaternion: model.boneRotationOffset, children: children }), boneObject) }, boneObject.id));
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated use CharacterModelBone instead
|
|
17
|
+
*/
|
|
18
|
+
export const VrmCharacterModelBone = CharacterModelBone;
|
package/dist/gamepad.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function useXRControllerInput(): Input<{}>;
|
|
1
|
+
export declare function useXRControllerInput(): void;
|
package/dist/gamepad.js
CHANGED
|
@@ -1,38 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JumpAction, MoveBackwardAction, MoveForwardAction, MoveLeftAction, MoveRightAction, } from '@pmndrs/viverse';
|
|
2
|
+
import { useFrame } from '@react-three/fiber';
|
|
2
3
|
import { useXRControllerButtonEvent, useXRInputSourceState } from '@react-three/xr';
|
|
3
|
-
import {
|
|
4
|
+
import { useEffect, useRef } from 'react';
|
|
4
5
|
export function useXRControllerInput() {
|
|
5
6
|
const leftController = useXRInputSourceState('controller', 'left');
|
|
6
|
-
const lastAPressed = useRef(null);
|
|
7
7
|
const rightController = useXRInputSourceState('controller', 'right');
|
|
8
|
-
useXRControllerButtonEvent(rightController, 'a-button', (state) => state === 'pressed' &&
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
return field === MoveLeftField ? Math.max(0, -thumbstickXAxis) : Math.max(0, thumbstickXAxis);
|
|
29
|
-
}
|
|
30
|
-
case LastTimeJumpPressedField:
|
|
31
|
-
return lastAPressed.current;
|
|
32
|
-
case RunField:
|
|
33
|
-
return (leftController?.gamepad?.['xr-standard-trigger']?.state === 'pressed');
|
|
34
|
-
}
|
|
35
|
-
return undefined;
|
|
36
|
-
},
|
|
37
|
-
}), [leftController]);
|
|
8
|
+
useXRControllerButtonEvent(rightController, 'a-button', (state) => state === 'pressed' && JumpAction.emit());
|
|
9
|
+
const forwardWriterRef = useRef(undefined);
|
|
10
|
+
const backwardWriterRef = useRef(undefined);
|
|
11
|
+
const leftWriterRef = useRef(undefined);
|
|
12
|
+
const rightWriterRef = useRef(undefined);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const abortController = new AbortController();
|
|
15
|
+
forwardWriterRef.current = MoveForwardAction.createWriter(abortController.signal);
|
|
16
|
+
backwardWriterRef.current = MoveBackwardAction.createWriter(abortController.signal);
|
|
17
|
+
leftWriterRef.current = MoveLeftAction.createWriter(abortController.signal);
|
|
18
|
+
rightWriterRef.current = MoveRightAction.createWriter(abortController.signal);
|
|
19
|
+
return () => abortController.abort();
|
|
20
|
+
}, [leftController]);
|
|
21
|
+
useFrame(() => {
|
|
22
|
+
forwardWriterRef.current?.write(-Math.min(0, leftController?.gamepad?.['xr-standard-thumbstick']?.yAxis ?? 0));
|
|
23
|
+
backwardWriterRef.current?.write(Math.max(0, leftController?.gamepad?.['xr-standard-thumbstick']?.yAxis ?? 0));
|
|
24
|
+
leftWriterRef.current?.write(-Math.min(0, leftController?.gamepad?.['xr-standard-thumbstick']?.xAxis ?? 0));
|
|
25
|
+
rightWriterRef.current?.write(Math.max(0, leftController?.gamepad?.['xr-standard-thumbstick']?.xAxis ?? 0));
|
|
26
|
+
});
|
|
38
27
|
}
|
package/dist/simple.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { RunAction, shouldJump, updateSimpleCharacterInputVelocity, updateSimpleCharacterRotation, } from '@pmndrs/viverse';
|
|
3
|
+
import { IdleAnimationUrl, JumpDownAnimationUrl, JumpForwardAnimationUrl, JumpLoopAnimationUrl, JumpUpAnimationUrl, RunAnimationUrl, WalkAnimationUrl, } from '@pmndrs/viverse/src/animation/default.js';
|
|
3
4
|
import { useFrame } from '@react-three/fiber';
|
|
4
5
|
import { Graph, GrapthState, Parallel, RunTimeline, Switch, SwitchCase, timePassed } from '@react-three/timeline';
|
|
5
6
|
import { forwardRef, Suspense, useImperativeHandle, useRef } from 'react';
|
|
@@ -8,20 +9,20 @@ import { CharacterAnimationAction } from './animation.js';
|
|
|
8
9
|
import { useViverseActiveAvatar } from './index.js';
|
|
9
10
|
import { CharacterModelProvider } from './model.js';
|
|
10
11
|
import { useBvhCharacterPhysics } from './physics.js';
|
|
11
|
-
import { useCharacterCameraBehavior, useCharacterModelLoader,
|
|
12
|
+
import { useCharacterCameraBehavior, useCharacterModelLoader, useSimpleCharacterInputs } from './utils.js';
|
|
12
13
|
export const SimpleCharacter = forwardRef(({ input, inputOptions, cameraBehavior, children, movement, physics: physicsOptions, model, useViverseAvatar, animation, ...props }, ref) => {
|
|
14
|
+
useSimpleCharacterInputs(input, inputOptions);
|
|
13
15
|
const internalRef = useRef(null);
|
|
14
|
-
|
|
15
|
-
useCharacterCameraBehavior(internalRef, inputSystem, cameraBehavior);
|
|
16
|
+
useCharacterCameraBehavior(internalRef, cameraBehavior);
|
|
16
17
|
const physics = useBvhCharacterPhysics(internalRef, physicsOptions);
|
|
17
18
|
const lastJumpTimeRef = useRef(-Infinity);
|
|
18
|
-
useFrame((state) => updateSimpleCharacterInputVelocity(state.camera,
|
|
19
|
+
useFrame((state) => updateSimpleCharacterInputVelocity(state.camera, physics, movement));
|
|
19
20
|
useFrame(() => {
|
|
20
21
|
if (model != false || movement?.jump === false) {
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
24
|
const bufferTime = movement?.jump === true ? undefined : movement?.jump?.bufferTime;
|
|
24
|
-
if (shouldJump(physics,
|
|
25
|
+
if (shouldJump(physics, lastJumpTimeRef.current, bufferTime)) {
|
|
25
26
|
lastJumpTimeRef.current = performance.now() / 1000;
|
|
26
27
|
physics.applyVelocity(
|
|
27
28
|
// eslint-disable-next-line @react-three/no-new-in-loop
|
|
@@ -29,9 +30,9 @@ export const SimpleCharacter = forwardRef(({ input, inputOptions, cameraBehavior
|
|
|
29
30
|
}
|
|
30
31
|
});
|
|
31
32
|
useImperativeHandle(ref, () => internalRef.current, []);
|
|
32
|
-
return (_jsx("group", { ...props, ref: internalRef, children: model == false ? (children) : (_jsx(SimpleCharacterModel, { animation: animation,
|
|
33
|
+
return (_jsx("group", { ...props, ref: internalRef, children: model == false ? (children) : (_jsx(SimpleCharacterModel, { animation: animation, physics: physics, model: model == true ? undefined : model, movement: movement, useViverseAvatar: useViverseAvatar, children: children })) }));
|
|
33
34
|
});
|
|
34
|
-
function SimpleCharacterModel({ children, model: modelOptions, movement, physics, useViverseAvatar = true,
|
|
35
|
+
function SimpleCharacterModel({ children, model: modelOptions, movement, physics, useViverseAvatar = true, animation, }) {
|
|
35
36
|
const avatar = useViverseActiveAvatar();
|
|
36
37
|
const model = useCharacterModelLoader(avatar != null && useViverseAvatar
|
|
37
38
|
? {
|
|
@@ -44,15 +45,15 @@ function SimpleCharacterModel({ children, model: modelOptions, movement, physics
|
|
|
44
45
|
useFrame((state, delta) => updateSimpleCharacterRotation(delta, physics, state.camera, model, animation));
|
|
45
46
|
return (_jsx(_Fragment, { children: _jsxs(CharacterModelProvider, { model: model, children: [_jsx(RunTimeline, { children: _jsxs(Graph, { enterState: "move", children: [_jsx(GrapthState, { name: "move", transitionTo: {
|
|
46
47
|
jumpStart: {
|
|
47
|
-
whenUpdate: () => shouldJump(physics,
|
|
48
|
+
whenUpdate: () => shouldJump(physics, lastJumpTimeRef.current),
|
|
48
49
|
},
|
|
49
50
|
jumpLoop: { whenUpdate: () => !physics.isGrounded },
|
|
50
|
-
}, children: _jsxs(Switch, { children: [_jsx(SwitchCase, { index: 0, condition: () => physics.inputVelocity.lengthSq() === 0, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.idle, fadeDuration: animation?.crossFadeDuration, url:
|
|
51
|
+
}, children: _jsxs(Switch, { children: [_jsx(SwitchCase, { index: 0, condition: () => physics.inputVelocity.lengthSq() === 0, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.idle, fadeDuration: animation?.crossFadeDuration, url: IdleAnimationUrl }) }) }), movement?.run != false && (_jsx(SwitchCase, { index: 1, condition: () => RunAction.get(), children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.run, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.8, url: RunAnimationUrl }) }) })), movement?.walk != false && (_jsx(SwitchCase, { index: 2, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.walk, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.5, url: WalkAnimationUrl }) }) })), _jsx(SwitchCase, { index: 3, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.idle, fadeDuration: animation?.crossFadeDuration, url: IdleAnimationUrl }) }) })] }) }), _jsx(GrapthState, { name: "jumpStart", transitionTo: {
|
|
51
52
|
jumpDown: { whenUpdate: () => !physics.isGrounded },
|
|
52
|
-
finally: () => (
|
|
53
|
-
}, children: _jsx(Parallel, { type: "race", children: _jsxs(Suspense, { fallback: null, children: [_jsx(CharacterAnimationAction, { ...animation?.jumpUp, fadeDuration: animation?.crossFadeDuration ?? 0.1, until: () => timePassed(0.2, 'seconds'), update: () => void physics.inputVelocity.multiplyScalar(0.3), paused: true, url:
|
|
53
|
+
finally: () => (RunAction.get() ? 'jumpForward' : 'jumpUp'),
|
|
54
|
+
}, children: _jsx(Parallel, { type: "race", children: _jsxs(Suspense, { fallback: null, children: [_jsx(CharacterAnimationAction, { ...animation?.jumpUp, fadeDuration: animation?.crossFadeDuration ?? 0.1, until: () => timePassed(0.2, 'seconds'), update: () => void physics.inputVelocity.multiplyScalar(0.3), paused: true, url: JumpUpAnimationUrl }), _jsx(CharacterAnimationAction, { ...animation?.jumpForward, fadeDuration: animation?.crossFadeDuration ?? 0.1, paused: true, url: JumpForwardAnimationUrl })] }) }) }), _jsx(GrapthState, { name: "jumpLoop", transitionTo: {
|
|
54
55
|
jumpDown: { whenUpdate: () => physics.isGrounded },
|
|
55
|
-
}, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpLoop, fadeDuration: animation?.crossFadeDuration, url:
|
|
56
|
+
}, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpLoop, fadeDuration: animation?.crossFadeDuration, url: JumpLoopAnimationUrl }) }) }), _jsx(GrapthState, { name: "jumpUp", transitionTo: {
|
|
56
57
|
jumpDown: {
|
|
57
58
|
whenUpdate: (_, _clock, actionTime) => actionTime > 0.3 && physics.isGrounded,
|
|
58
59
|
},
|
|
@@ -60,8 +61,8 @@ function SimpleCharacterModel({ children, model: modelOptions, movement, physics
|
|
|
60
61
|
}, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpUp, fadeDuration: animation?.crossFadeDuration, loop: LoopOnce, init: () => {
|
|
61
62
|
lastJumpTimeRef.current = performance.now() / 1000;
|
|
62
63
|
physics.applyVelocity(new Vector3(0, (typeof movement?.jump === 'object' ? movement?.jump.speed : undefined) ?? 8, 0));
|
|
63
|
-
}, url:
|
|
64
|
+
}, url: JumpUpAnimationUrl }) }) }), _jsx(GrapthState, { name: "jumpForward", transitionTo: { finally: () => (physics.isGrounded ? 'move' : 'jumpLoop') }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpForward, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.9, init: () => {
|
|
64
65
|
lastJumpTimeRef.current = performance.now() / 1000;
|
|
65
66
|
physics.applyVelocity(new Vector3(0, 8, 0));
|
|
66
|
-
}, loop: LoopOnce, url:
|
|
67
|
+
}, loop: LoopOnce, url: JumpForwardAnimationUrl }) }) }), _jsx(GrapthState, { name: "jumpDown", transitionTo: { finally: 'move' }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpDown, fadeDuration: animation?.crossFadeDuration, until: () => timePassed(150, 'milliseconds'), loop: LoopOnce, url: JumpDownAnimationUrl }) }) })] }) }), _jsx("primitive", { object: model.scene }), children] }) }));
|
|
67
68
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { CharacterAnimationOptions, CharacterModelOptions,
|
|
1
|
+
import { CharacterCameraBehavior, CharacterAnimationOptions, CharacterModelOptions, SimpleCharacterCameraBehaviorOptions, CharacterModel, SimpleCharacterInputOptions } from '@pmndrs/viverse';
|
|
2
2
|
import { RefObject } from 'react';
|
|
3
3
|
import { Object3D } from 'three';
|
|
4
|
-
export declare function useCharacterCameraBehavior(model: Object3D | RefObject<Object3D | null>,
|
|
4
|
+
export declare function useCharacterCameraBehavior(model: Object3D | RefObject<Object3D | null>, options?: SimpleCharacterCameraBehaviorOptions): RefObject<CharacterCameraBehavior | undefined>;
|
|
5
5
|
export declare function useCharacterModelLoader(options?: CharacterModelOptions): CharacterModel;
|
|
6
6
|
export declare function useCharacterAnimationLoader(model: CharacterModel, options: CharacterAnimationOptions): import("three").AnimationClip;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated use inputs directly
|
|
9
|
+
*/
|
|
10
|
+
export declare function useSimpleCharacterInputs(inputsClasses?: ReadonlyArray<{
|
|
11
|
+
new (domElement: HTMLElement): {
|
|
12
|
+
dispose(): void;
|
|
13
|
+
};
|
|
14
|
+
}>, options?: SimpleCharacterInputOptions): void;
|
package/dist/utils.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { VRM } from '@pixiv/three-vrm';
|
|
2
|
-
import { CharacterCameraBehavior, flattenCharacterAnimationOptions, flattenCharacterModelOptions,
|
|
2
|
+
import { CharacterCameraBehavior, flattenCharacterAnimationOptions, flattenCharacterModelOptions, loadCharacterModel, loadCharacterAnimation, ScreenJoystickInput, ScreenJumpButtonInput, PointerCaptureInput, LocomotionKeyboardInput, applySimpleCharacterInputOptions, } from '@pmndrs/viverse';
|
|
3
3
|
import { useFrame, useThree } from '@react-three/fiber';
|
|
4
|
-
import { useEffect, useMemo } from 'react';
|
|
4
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
5
5
|
import { suspend } from 'suspend-react';
|
|
6
6
|
import { Object3D } from 'three';
|
|
7
7
|
import { useBvhPhysicsWorld } from './physics.js';
|
|
8
|
-
export function useCharacterCameraBehavior(model,
|
|
9
|
-
const
|
|
8
|
+
export function useCharacterCameraBehavior(model, options) {
|
|
9
|
+
const behaviorRef = useRef(undefined);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const behavior = new CharacterCameraBehavior();
|
|
12
|
+
behaviorRef.current = behavior;
|
|
13
|
+
return () => {
|
|
14
|
+
behaviorRef.current = undefined;
|
|
15
|
+
behavior.dispose();
|
|
16
|
+
};
|
|
17
|
+
}, []);
|
|
10
18
|
const world = useBvhPhysicsWorld();
|
|
11
19
|
const raycast = useMemo(() => world.raycast.bind(world), [world]);
|
|
12
20
|
useFrame((state, delta) => {
|
|
@@ -14,8 +22,9 @@ export function useCharacterCameraBehavior(model, inputSystem, options) {
|
|
|
14
22
|
if (resolvedModel == null) {
|
|
15
23
|
return;
|
|
16
24
|
}
|
|
17
|
-
|
|
25
|
+
behaviorRef.current?.update(state.camera, resolvedModel, delta, raycast, options);
|
|
18
26
|
});
|
|
27
|
+
return behaviorRef;
|
|
19
28
|
}
|
|
20
29
|
const loadCharacterModelSymbol = Symbol('loadCharacterModel');
|
|
21
30
|
export function useCharacterModelLoader(options) {
|
|
@@ -32,36 +41,39 @@ const loadCharacterAnimationSymbol = Symbol('loadCharacterAnimation');
|
|
|
32
41
|
export function useCharacterAnimationLoader(model, options) {
|
|
33
42
|
return suspend((_, ...params) => loadCharacterAnimation(...params), [loadCharacterAnimationSymbol, model, ...flattenCharacterAnimationOptions(options)]);
|
|
34
43
|
}
|
|
35
|
-
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated use inputs directly
|
|
46
|
+
*/
|
|
47
|
+
export function useSimpleCharacterInputs(inputsClasses = [
|
|
36
48
|
ScreenJoystickInput,
|
|
37
49
|
ScreenJumpButtonInput,
|
|
38
50
|
PointerCaptureInput,
|
|
39
51
|
LocomotionKeyboardInput,
|
|
40
|
-
], options
|
|
52
|
+
], options) {
|
|
41
53
|
const dom = useThree((s) => s.gl.domElement);
|
|
42
|
-
const optionsRef = useMemo(() => ({}), []);
|
|
43
|
-
//clearing and copying the options to optionsRef
|
|
44
|
-
for (const key in optionsRef) {
|
|
45
|
-
delete optionsRef[key];
|
|
46
|
-
}
|
|
47
|
-
Object.assign(optionsRef, options);
|
|
48
54
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
49
|
-
const
|
|
55
|
+
const inputs = useMemo(() => [], [dom]);
|
|
50
56
|
useEffect(() => {
|
|
51
|
-
const removedInputs = new Set(
|
|
52
|
-
for (const
|
|
53
|
-
const existingInput =
|
|
57
|
+
const removedInputs = new Set(inputs);
|
|
58
|
+
for (const inputClass of inputsClasses) {
|
|
59
|
+
const existingInput = inputs.find((existingInput) => existingInput instanceof inputClass);
|
|
54
60
|
if (existingInput != null) {
|
|
55
61
|
removedInputs.delete(existingInput);
|
|
56
62
|
continue;
|
|
57
63
|
}
|
|
58
|
-
|
|
64
|
+
inputs.push(new inputClass(dom));
|
|
59
65
|
}
|
|
60
66
|
for (const removedInput of removedInputs) {
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
removedInput.dispose();
|
|
68
|
+
const index = inputs.indexOf(removedInput);
|
|
69
|
+
if (index != -1) {
|
|
70
|
+
inputs.splice(index, 1);
|
|
71
|
+
}
|
|
63
72
|
}
|
|
73
|
+
applySimpleCharacterInputOptions(inputs, options);
|
|
64
74
|
});
|
|
65
|
-
useEffect(() => () =>
|
|
66
|
-
|
|
75
|
+
useEffect(() => () => {
|
|
76
|
+
inputs.forEach((input) => input.dispose());
|
|
77
|
+
inputs.length = 0;
|
|
78
|
+
}, [inputs]);
|
|
67
79
|
}
|
package/package.json
CHANGED
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@viverse/sdk": "^1.2.10-alpha.0",
|
|
27
|
-
"@react-three/timeline": "^0.3.
|
|
27
|
+
"@react-three/timeline": "^0.3.7",
|
|
28
28
|
"suspend-react": "^0.1.3",
|
|
29
29
|
"@pixiv/three-vrm": "^3.4.2",
|
|
30
30
|
"zustand": "^5.0.6",
|
|
31
31
|
"@react-three/xr": "^6.6.20",
|
|
32
|
-
"@pmndrs/viverse": "^0.2.
|
|
32
|
+
"@pmndrs/viverse": "^0.2.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@react-three/fiber": "*"
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@types/react": "^19.1.8",
|
|
41
41
|
"react": "^19.1.0"
|
|
42
42
|
},
|
|
43
|
-
"version": "0.2.
|
|
43
|
+
"version": "0.2.1",
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "tsc",
|
|
46
46
|
"check:prettier": "prettier --check src",
|