standardize source naming conventions

This commit is contained in:
2026-04-28 14:46:27 +02:00
parent 7e99d455b4
commit e20ead88e1
19 changed files with 33 additions and 33 deletions
+173
View File
@@ -0,0 +1,173 @@
import { useCallback, useEffect, useRef } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import type { RapierRigidBody } from "@react-three/rapier";
import * as THREE from "three";
import type GUI from "lil-gui";
import type { RefObject } from "react";
import {
INTERACTION_DEBUG_SPHERE_COLOR,
INTERACTION_DEBUG_SPHERE_OPACITY,
INTERACTION_DEBUG_SPHERE_SEGMENTS,
} from "@/data/debug/debugConfig";
import { Debug } from "@/utils/debug/Debug";
import { useDebugFolder } from "@/hooks/debug/useDebugFolder";
import { InteractionManager } from "@/managers/InteractionManager";
import { INTERACTION_RADIUS } from "@/data/interaction/interactionConfig";
import type { Vector3Tuple } from "@/types/three";
import type { InteractableHandle } from "@/types/interaction";
interface InteractableObjectBaseProps {
label: string;
position: Vector3Tuple;
bodyRef?: RefObject<RapierRigidBody | null>;
onPress: () => void;
children: React.ReactNode;
}
interface TriggerInteractableObjectProps extends InteractableObjectBaseProps {
kind: "trigger";
}
interface GrabInteractableObjectProps extends InteractableObjectBaseProps {
kind: "grab";
onRelease: () => void;
}
type InteractableObjectProps =
| TriggerInteractableObjectProps
| GrabInteractableObjectProps;
const _cameraPos = new THREE.Vector3();
const _cameraDir = new THREE.Vector3();
const _objectPos = new THREE.Vector3();
const _raycaster = new THREE.Raycaster();
function createInteractableHandle(
props: InteractableObjectProps,
): InteractableHandle {
if (props.kind === "grab") {
return {
kind: props.kind,
label: props.label,
onPress: props.onPress,
onRelease: props.onRelease,
};
}
return {
kind: props.kind,
label: props.label,
onPress: props.onPress,
};
}
export function InteractableObject(
props: InteractableObjectProps,
): React.JSX.Element {
const { kind, label, position, bodyRef, onPress, children } = props;
const onRelease = props.kind === "grab" ? props.onRelease : null;
const camera = useThree((state) => state.camera);
const groupRef = useRef<THREE.Group>(null);
const debugSphereRef = useRef<THREE.Mesh>(null);
const handle = useRef<InteractableHandle>(createInteractableHandle(props));
useEffect(() => {
const currentHandle = handle.current;
if (currentHandle.kind === kind) {
currentHandle.label = label;
currentHandle.onPress = onPress;
if (currentHandle.kind === "grab") {
if (!onRelease) return;
currentHandle.onRelease = onRelease;
}
return;
}
if (kind === "grab") {
if (!onRelease) return;
handle.current = { kind, label, onPress, onRelease };
} else {
handle.current = { kind, label, onPress };
}
const manager = InteractionManager.getInstance();
if (manager.getState().focused === currentHandle) {
manager.setFocused(handle.current);
}
}, [kind, label, onPress, onRelease]);
const setupInteractionDebugFolder = useCallback((folder: GUI) => {
folder
.add({ radius: INTERACTION_RADIUS }, "radius")
.name("Interaction radius")
.disable();
}, []);
useDebugFolder("Interaction", setupInteractionDebugFolder);
useFrame(() => {
const group = groupRef.current;
const debug = Debug.getInstance();
const manager = InteractionManager.getInstance();
if (debugSphereRef.current) {
debugSphereRef.current.visible =
debug.active && debug.getShowInteractionSpheres();
}
if (bodyRef?.current) {
const t = bodyRef.current.translation();
_objectPos.set(t.x, t.y, t.z);
} else {
_objectPos.set(...position);
}
camera.getWorldPosition(_cameraPos);
const dist = _cameraPos.distanceTo(_objectPos);
if (dist > INTERACTION_RADIUS) {
if (manager.getState().focused === handle.current) {
manager.setFocused(null);
}
return;
}
camera.getWorldDirection(_cameraDir);
_raycaster.set(_cameraPos, _cameraDir);
_raycaster.far = INTERACTION_RADIUS;
const hits = group ? _raycaster.intersectObject(group, true) : [];
const validHit = hits.find((h) => h.object !== debugSphereRef.current);
if (validHit) {
manager.setFocused(handle.current);
} else if (manager.getState().focused === handle.current) {
manager.setFocused(null);
}
});
return (
<group ref={groupRef}>
{children}
<mesh ref={debugSphereRef} visible={false}>
<sphereGeometry
args={[
INTERACTION_RADIUS,
INTERACTION_DEBUG_SPHERE_SEGMENTS,
INTERACTION_DEBUG_SPHERE_SEGMENTS,
]}
/>
<meshBasicMaterial
color={INTERACTION_DEBUG_SPHERE_COLOR}
wireframe
transparent
opacity={INTERACTION_DEBUG_SPHERE_OPACITY}
/>
</mesh>
</group>
);
}