Files
healer-man/src/scene/PrototypeDungeon.tsx
T
2026-08-22 15:53:43 -04:00

91 lines
3.5 KiB
TypeScript

import { Sparkles } from "@react-three/drei";
import { RigidBody } from "@react-three/rapier";
import type { DungeonDefinition } from "../game/dungeonTypes";
import {
DUNGEON_PHYSICAL_COLLISION_GROUPS,
DUNGEON_WALL_COLLISION_GROUPS,
} from "./dungeonLineOfSight";
interface SlabProps {
position: [number, number, number];
size: [number, number, number];
rotationY?: number;
color?: string;
blocksLineOfSight?: boolean;
}
function CaveSlab({
position,
size,
rotationY = 0,
color = "#25352b",
blocksLineOfSight = false,
}: SlabProps) {
return (
<RigidBody
type="fixed"
colliders="cuboid"
collisionGroups={blocksLineOfSight
? DUNGEON_WALL_COLLISION_GROUPS
: DUNGEON_PHYSICAL_COLLISION_GROUPS}
position={position}
rotation={[0, rotationY, 0]}
>
<mesh receiveShadow castShadow>
<boxGeometry args={size} />
<meshStandardMaterial color={color} roughness={0.96} metalness={0.02} />
</mesh>
</RigidBody>
);
}
const stonePositions: ReadonlyArray<readonly [number, number, number, number]> = [
[-3.5, 0.7, -1, 0.8], [3.4, 0.9, 2, 1], [-3.7, 1.1, 7, 1.15], [3.6, 0.65, 11, 0.75],
[-3.6, 0.8, 16, 0.9], [3.5, 1.2, 20, 1.2], [-7.2, 0.85, 27, 1], [7.5, 1.15, 25, 1.2],
[-8.1, 0.7, 34, 0.85], [8.2, 0.95, 35, 1.05], [-5.5, 0.72, 42, 0.85], [11.7, 1.1, 43, 1.2],
];
function Stone({ position }: { position: readonly [number, number, number, number] }) {
return (
<mesh castShadow position={[position[0], position[1], position[2]]} scale={[position[3], position[3] * 1.7, position[3]]}>
<dodecahedronGeometry args={[0.85, 0]} />
<meshStandardMaterial color="#33453a" roughness={1} />
</mesh>
);
}
export function PrototypeDungeon({ definition }: { readonly definition: DungeonDefinition }) {
const entrance = definition.entrance;
return (
<group
name={`${definition.id}-proxy`}
position={entrance.footPosition}
rotation={[0, entrance.yaw, 0]}
>
<CaveSlab position={[0, -0.3, 11]} size={[7.4, 0.6, 28]} />
<CaveSlab position={[-4.1, 2.15, 11]} size={[1.1, 4.9, 28]} color="#1c2c24" blocksLineOfSight />
<CaveSlab position={[4.1, 2.15, 11]} size={[1.1, 4.9, 28]} color="#1c2c24" blocksLineOfSight />
<CaveSlab position={[0, -0.36, 31]} size={[18, 0.72, 15]} color="#2b3d31" />
<CaveSlab position={[-9.25, 2, 31]} size={[1.1, 4.7, 15]} color="#1b2a23" blocksLineOfSight />
<CaveSlab position={[9.25, 2, 31]} size={[1.1, 4.7, 15]} color="#1b2a23" blocksLineOfSight />
<CaveSlab position={[3.3, -0.3, 44]} size={[9, 0.6, 19]} rotationY={-0.34} />
{stonePositions.map((position, index) => <Stone key={index} position={position} />)}
<mesh position={[-1.7, 4.25, 15]} rotation={[0, 0, Math.PI / 2]}>
<torusGeometry args={[3.1, 0.42, 8, 16, Math.PI]} />
<meshStandardMaterial color="#27382d" roughness={1} />
</mesh>
<mesh position={[2.4, 4.5, 36]} rotation={[0, 0, Math.PI / 2]}>
<torusGeometry args={[4.2, 0.58, 8, 18, Math.PI]} />
<meshStandardMaterial color="#304338" roughness={1} />
</mesh>
<pointLight position={[-1.9, 2.1, 5]} color="#d1a64d" intensity={9} distance={13} decay={2} />
<pointLight position={[5.2, 2.4, 30]} color="#4eaa7a" intensity={13} distance={18} decay={2} />
<pointLight position={[-4.7, 1.8, 38]} color="#8fbd68" intensity={10} distance={15} decay={2} />
<Sparkles count={85} scale={[17, 6, 53]} position={[0, 2.5, 24]} size={1.4} speed={0.2} color="#9fc58c" opacity={0.45} />
</group>
);
}