refactor: organize three components by domain
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { RigidBody } from "@react-three/rapier";
|
||||
import { InteractableObject } from "@/components/three/interaction/InteractableObject";
|
||||
import {
|
||||
TRIGGER_DEFAULT_COLLIDERS,
|
||||
TRIGGER_DEFAULT_LABEL,
|
||||
TRIGGER_DEFAULT_SOUND_VOLUME,
|
||||
TRIGGER_DEFAULT_SPAWN_OFFSET,
|
||||
} from "@/data/interaction/triggerConfig";
|
||||
import { AudioManager } from "@/managers/AudioManager";
|
||||
import type { ColliderShape, Vector3Tuple } from "@/types/three";
|
||||
|
||||
interface SpawnedModel {
|
||||
id: number;
|
||||
position: Vector3Tuple;
|
||||
}
|
||||
|
||||
interface TriggerObjectProps {
|
||||
position: Vector3Tuple;
|
||||
children: React.ReactNode;
|
||||
colliders?: ColliderShape;
|
||||
label?: string;
|
||||
soundPath?: string;
|
||||
soundVolume?: number;
|
||||
spawnModel?: string;
|
||||
spawnOffset?: Vector3Tuple;
|
||||
onTrigger?: () => void;
|
||||
}
|
||||
|
||||
let spawnCounter = 0;
|
||||
|
||||
function SpawnedModelInstance({
|
||||
path,
|
||||
position,
|
||||
}: {
|
||||
path: string;
|
||||
position: Vector3Tuple;
|
||||
}): React.JSX.Element {
|
||||
const { scene } = useGLTF(path);
|
||||
const model = useMemo(() => scene.clone(true), [scene]);
|
||||
|
||||
return <primitive object={model} position={position} />;
|
||||
}
|
||||
|
||||
export function TriggerObject({
|
||||
position,
|
||||
children,
|
||||
colliders = TRIGGER_DEFAULT_COLLIDERS,
|
||||
label = TRIGGER_DEFAULT_LABEL,
|
||||
soundPath,
|
||||
soundVolume = TRIGGER_DEFAULT_SOUND_VOLUME,
|
||||
spawnModel,
|
||||
spawnOffset = TRIGGER_DEFAULT_SPAWN_OFFSET,
|
||||
onTrigger,
|
||||
}: TriggerObjectProps): React.JSX.Element {
|
||||
const [spawned, setSpawned] = useState<SpawnedModel[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<RigidBody type="fixed" colliders={colliders} position={position}>
|
||||
<InteractableObject
|
||||
kind="trigger"
|
||||
label={label}
|
||||
position={position}
|
||||
onPress={() => {
|
||||
if (soundPath) {
|
||||
AudioManager.getInstance().playSound(soundPath, soundVolume);
|
||||
}
|
||||
|
||||
onTrigger?.();
|
||||
|
||||
if (spawnModel) {
|
||||
const spawnPos: Vector3Tuple = [
|
||||
position[0] + spawnOffset[0],
|
||||
position[1] + spawnOffset[1],
|
||||
position[2] + spawnOffset[2],
|
||||
];
|
||||
setSpawned((prev) => [
|
||||
...prev,
|
||||
{ id: ++spawnCounter, position: spawnPos },
|
||||
]);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</InteractableObject>
|
||||
</RigidBody>
|
||||
|
||||
{spawnModel &&
|
||||
spawned.map((s) => (
|
||||
<SpawnedModelInstance
|
||||
key={s.id}
|
||||
path={spawnModel}
|
||||
position={s.position}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user