91 lines
3.5 KiB
TypeScript
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>
|
|
);
|
|
}
|