clean
This commit is contained in:
@@ -14,11 +14,7 @@ import { useDebugFolder } from "@/hooks/debug/useDebugFolder";
|
||||
import { InteractionManager } from "@/stateManager/InteractionManager";
|
||||
import { INTERACTION_RADIUS } from "@/data/interactionConfig";
|
||||
import type { Vector3Tuple } from "@/types/3d";
|
||||
import type {
|
||||
GrabInteractableHandle,
|
||||
InteractableHandle,
|
||||
TriggerInteractableHandle,
|
||||
} from "@/types/interaction";
|
||||
import type { InteractableHandle, InteractableKind } from "@/types/interaction";
|
||||
|
||||
interface InteractableObjectBaseProps {
|
||||
label: string;
|
||||
@@ -41,6 +37,13 @@ type InteractableObjectProps =
|
||||
| TriggerInteractableObjectProps
|
||||
| GrabInteractableObjectProps;
|
||||
|
||||
type MutableInteractableHandle = {
|
||||
kind: InteractableKind;
|
||||
label: string;
|
||||
onPress: () => void;
|
||||
onRelease?: () => void;
|
||||
};
|
||||
|
||||
const _cameraPos = new THREE.Vector3();
|
||||
const _cameraDir = new THREE.Vector3();
|
||||
const _objectPos = new THREE.Vector3();
|
||||
@@ -50,6 +53,7 @@ export function InteractableObject(
|
||||
props: InteractableObjectProps,
|
||||
): React.JSX.Element {
|
||||
const { kind, label, position, bodyRef, onPress, children } = props;
|
||||
const onRelease = props.kind === "grab" ? props.onRelease : undefined;
|
||||
const camera = useThree((state) => state.camera);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const debugSphereRef = useRef<THREE.Mesh>(null);
|
||||
@@ -61,27 +65,19 @@ export function InteractableObject(
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.kind === "grab") {
|
||||
const current = handle.current as GrabInteractableHandle;
|
||||
current.label = label;
|
||||
current.onPress = onPress;
|
||||
current.onRelease = props.onRelease;
|
||||
const current = handle.current as MutableInteractableHandle;
|
||||
current.kind = kind;
|
||||
current.label = label;
|
||||
current.onPress = onPress;
|
||||
|
||||
if (kind === "grab" && onRelease) {
|
||||
current.onRelease = onRelease;
|
||||
return;
|
||||
}
|
||||
|
||||
delete current.onRelease;
|
||||
return undefined;
|
||||
}, [label, onPress, props]);
|
||||
|
||||
useEffect(() => {
|
||||
if (kind === "grab") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const current = handle.current as TriggerInteractableHandle;
|
||||
current.label = label;
|
||||
current.onPress = onPress;
|
||||
return undefined;
|
||||
}, [kind, label, onPress]);
|
||||
}, [kind, label, onPress, onRelease]);
|
||||
|
||||
const setupInteractionDebugFolder = useCallback((folder: GUI) => {
|
||||
folder
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { Vector3Tuple } from "@/types/3d";
|
||||
|
||||
export const PLAYER_EYE_HEIGHT = 1.75;
|
||||
export const PLAYER_CAPSULE_RADIUS = 0.35;
|
||||
|
||||
@@ -9,7 +11,5 @@ export const PLAYER_MAX_DELTA = 0.05;
|
||||
export const PLAYER_ACCELERATION_MULTIPLIER = 9;
|
||||
export const PLAYER_XZ_DAMPING_FACTOR = 8;
|
||||
|
||||
export const PLAYER_SPAWN_X = 0;
|
||||
export const PLAYER_SPAWN_Z = 0;
|
||||
export const PLAYER_SPAWN_Y_GAME = 100;
|
||||
export const PLAYER_SPAWN_Y_PHYSICS = 3;
|
||||
export const PLAYER_SPAWN_POSITION_GAME: Vector3Tuple = [0, 100, 0];
|
||||
export const PLAYER_SPAWN_POSITION_PHYSICS: Vector3Tuple = [0, 3, 0];
|
||||
|
||||
@@ -4,11 +4,13 @@ import {
|
||||
DEBUG_CAMERA_MAX_DISTANCE,
|
||||
DEBUG_CAMERA_MIN_DISTANCE,
|
||||
} from "@/data/debugConfig";
|
||||
import {
|
||||
import { PLAYER_EYE_HEIGHT, PLAYER_SPAWN_POSITION_GAME } from "@/data/playerConfig";
|
||||
|
||||
const DEBUG_CAMERA_TARGET = [
|
||||
PLAYER_SPAWN_POSITION_GAME[0],
|
||||
PLAYER_EYE_HEIGHT,
|
||||
PLAYER_SPAWN_X,
|
||||
PLAYER_SPAWN_Z,
|
||||
} from "@/data/playerConfig";
|
||||
PLAYER_SPAWN_POSITION_GAME[2],
|
||||
] as const;
|
||||
|
||||
export function DebugCameraControls(): React.JSX.Element {
|
||||
return (
|
||||
@@ -17,7 +19,7 @@ export function DebugCameraControls(): React.JSX.Element {
|
||||
dampingFactor={DEBUG_CAMERA_DAMPING_FACTOR}
|
||||
minDistance={DEBUG_CAMERA_MIN_DISTANCE}
|
||||
maxDistance={DEBUG_CAMERA_MAX_DISTANCE}
|
||||
target={[PLAYER_SPAWN_X, PLAYER_EYE_HEIGHT, PLAYER_SPAWN_Z]}
|
||||
target={DEBUG_CAMERA_TARGET}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
+7
-5
@@ -1,8 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import type { Octree } from "three/addons/math/Octree.js";
|
||||
import {
|
||||
PLAYER_SPAWN_Y_GAME,
|
||||
PLAYER_SPAWN_Y_PHYSICS,
|
||||
PLAYER_SPAWN_POSITION_GAME,
|
||||
PLAYER_SPAWN_POSITION_PHYSICS,
|
||||
} from "@/data/playerConfig";
|
||||
import { useCameraMode } from "@/hooks/debug/useCameraMode";
|
||||
import { useSceneMode } from "@/hooks/debug/useSceneMode";
|
||||
@@ -18,6 +18,10 @@ export function World(): React.JSX.Element {
|
||||
const cameraMode = useCameraMode();
|
||||
const sceneMode = useSceneMode();
|
||||
const [octree, setOctree] = useState<Octree | null>(null);
|
||||
const playerSpawnPosition =
|
||||
sceneMode === "game"
|
||||
? PLAYER_SPAWN_POSITION_GAME
|
||||
: PLAYER_SPAWN_POSITION_PHYSICS;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -35,9 +39,7 @@ export function World(): React.JSX.Element {
|
||||
{cameraMode !== "debug" ? (
|
||||
<PlayerComponent
|
||||
octree={octree}
|
||||
spawnY={
|
||||
sceneMode === "game" ? PLAYER_SPAWN_Y_GAME : PLAYER_SPAWN_Y_PHYSICS
|
||||
}
|
||||
spawnPosition={playerSpawnPosition}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import { useEffect } from "react";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import type { Octree } from "three/addons/math/Octree.js";
|
||||
import { PLAYER_SPAWN_X, PLAYER_SPAWN_Z } from "@/data/playerConfig";
|
||||
import type { Vector3Tuple } from "@/types/3d";
|
||||
import { PlayerCamera } from "@/world/player/PlayerCamera";
|
||||
import { PlayerController } from "@/world/player/PlayerController";
|
||||
|
||||
interface PlayerComponentProps {
|
||||
octree: Octree | null;
|
||||
spawnY: number;
|
||||
spawnPosition: Vector3Tuple;
|
||||
}
|
||||
|
||||
export function PlayerComponent({
|
||||
spawnY,
|
||||
spawnPosition,
|
||||
octree,
|
||||
}: PlayerComponentProps): React.JSX.Element {
|
||||
const camera = useThree((state) => state.camera);
|
||||
|
||||
useEffect(() => {
|
||||
camera.position.set(PLAYER_SPAWN_X, spawnY, PLAYER_SPAWN_Z);
|
||||
}, [camera, spawnY]);
|
||||
camera.position.set(...spawnPosition);
|
||||
}, [camera, spawnPosition]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PlayerCamera />
|
||||
<PlayerController octree={octree} />
|
||||
<PlayerController octree={octree} spawnPosition={spawnPosition} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,12 +20,11 @@ import {
|
||||
PLAYER_GRAVITY,
|
||||
PLAYER_JUMP_SPEED,
|
||||
PLAYER_MAX_DELTA,
|
||||
PLAYER_SPAWN_X,
|
||||
PLAYER_SPAWN_Z,
|
||||
PLAYER_WALK_SPEED,
|
||||
PLAYER_XZ_DAMPING_FACTOR,
|
||||
} from "@/data/playerConfig";
|
||||
import { InteractionManager } from "@/stateManager/InteractionManager";
|
||||
import type { Vector3Tuple } from "@/types/3d";
|
||||
|
||||
type Keys = {
|
||||
forward: boolean;
|
||||
@@ -45,6 +44,7 @@ const DEFAULT_KEYS: Keys = {
|
||||
|
||||
interface PlayerControllerProps {
|
||||
octree: Octree | null;
|
||||
spawnPosition: Vector3Tuple;
|
||||
}
|
||||
|
||||
const _forward = new THREE.Vector3();
|
||||
@@ -52,8 +52,12 @@ const _right = new THREE.Vector3();
|
||||
const _wishDir = new THREE.Vector3();
|
||||
const _up = new THREE.Vector3(0, 1, 0);
|
||||
const _translateVec = new THREE.Vector3();
|
||||
const _collisionCorrection = new THREE.Vector3();
|
||||
|
||||
export function PlayerController({ octree }: PlayerControllerProps): null {
|
||||
export function PlayerController({
|
||||
octree,
|
||||
spawnPosition,
|
||||
}: PlayerControllerProps): null {
|
||||
const camera = useThree((state) => state.camera);
|
||||
const keys = useRef<Keys>({ ...DEFAULT_KEYS });
|
||||
const velocity = useRef(new THREE.Vector3());
|
||||
@@ -69,14 +73,17 @@ export function PlayerController({ octree }: PlayerControllerProps): null {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const spawnY = camera.position.y;
|
||||
capsule.current.start.set(
|
||||
PLAYER_SPAWN_X,
|
||||
spawnY - PLAYER_EYE_HEIGHT + PLAYER_CAPSULE_RADIUS,
|
||||
PLAYER_SPAWN_Z,
|
||||
spawnPosition[0],
|
||||
spawnPosition[1] - PLAYER_EYE_HEIGHT + PLAYER_CAPSULE_RADIUS,
|
||||
spawnPosition[2],
|
||||
);
|
||||
capsule.current.end.set(PLAYER_SPAWN_X, spawnY, PLAYER_SPAWN_Z);
|
||||
}, [camera]);
|
||||
capsule.current.end.set(...spawnPosition);
|
||||
velocity.current.set(0, 0, 0);
|
||||
onFloor.current = false;
|
||||
wantsJump.current = false;
|
||||
camera.position.copy(capsule.current.end);
|
||||
}, [camera, spawnPosition]);
|
||||
|
||||
useEffect(() => {
|
||||
const interaction = InteractionManager.getInstance();
|
||||
@@ -215,7 +222,7 @@ export function PlayerController({ octree }: PlayerControllerProps): null {
|
||||
}
|
||||
|
||||
capsule.current.translate(
|
||||
result.normal.clone().multiplyScalar(result.depth),
|
||||
_collisionCorrection.copy(result.normal).multiplyScalar(result.depth),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user