Release Healer Man 0.1.21
This commit is contained in:
1 parent
699fc858c9
commit
f6f2375145
210 files changed
+976039
-6247
No files matched your search
@@ -0,0 +1,95 @@
|
||||
import { CuboidCollider, RigidBody } from "@react-three/rapier";
|
||||
import { useMemo, useSyncExternalStore } from "react";
|
||||
import type { Object3D } from "three";
|
||||
import {
|
||||
activeDungeonEncounterRevision,
|
||||
subscribeDungeonEncounterSnapshots,
|
||||
} from "../game/dungeonEncounterRuntime";
|
||||
import { activeDungeonWorldObjectStates } from "../game/dungeonWorldInteraction";
|
||||
import {
|
||||
dungeonWorldObjectState,
|
||||
type DungeonWorldObjectDefinition,
|
||||
} from "../game/dungeonWorldObjects";
|
||||
import {
|
||||
DUNGEON_PHYSICAL_COLLISION_GROUPS,
|
||||
DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS,
|
||||
} from "./dungeonLineOfSight";
|
||||
import { useGameGLTF } from "./useGameGLTF";
|
||||
|
||||
function AssetObject({ definition }: { readonly definition: DungeonWorldObjectDefinition }) {
|
||||
const gltf = useGameGLTF(definition.visual!.assetUrl!);
|
||||
const visual = useMemo<Object3D>(() => gltf.scene.clone(true), [gltf.scene]);
|
||||
return <primitive object={visual} scale={definition.visual?.scale ?? [1, 1, 1]} />;
|
||||
}
|
||||
|
||||
function ProceduralObject({ definition }: { readonly definition: DungeonWorldObjectDefinition }) {
|
||||
const [x, y, z] = definition.halfExtents;
|
||||
return (
|
||||
<mesh castShadow receiveShadow>
|
||||
<boxGeometry args={[x * 2, y * 2, z * 2]} />
|
||||
<meshStandardMaterial
|
||||
color={definition.visual?.color ?? (definition.kind === "switch" ? "#dca24a" : "#65584b")}
|
||||
emissive={definition.visual?.emissive ?? "#000000"}
|
||||
roughness={0.72}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
function WorldObject({
|
||||
definition,
|
||||
stateId,
|
||||
}: {
|
||||
readonly definition: DungeonWorldObjectDefinition;
|
||||
readonly stateId?: string;
|
||||
}) {
|
||||
const state = dungeonWorldObjectState(definition, stateId);
|
||||
if (!state.visible) return null;
|
||||
return (
|
||||
<RigidBody
|
||||
key={`${definition.id}:${state.id}`}
|
||||
type="fixed"
|
||||
colliders={false}
|
||||
position={definition.position}
|
||||
rotation={[0, definition.yaw ?? 0, 0]}
|
||||
name={`dungeon-object:${definition.id}:${state.id}`}
|
||||
>
|
||||
{state.blocksMovement && (
|
||||
<CuboidCollider
|
||||
args={[...definition.halfExtents]}
|
||||
collisionGroups={DUNGEON_PHYSICAL_COLLISION_GROUPS}
|
||||
/>
|
||||
)}
|
||||
{state.blocksSight && (
|
||||
<CuboidCollider
|
||||
args={[...definition.halfExtents]}
|
||||
collisionGroups={DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS}
|
||||
sensor
|
||||
/>
|
||||
)}
|
||||
{definition.visual?.assetUrl
|
||||
? <AssetObject definition={definition} />
|
||||
: <ProceduralObject definition={definition} />}
|
||||
</RigidBody>
|
||||
);
|
||||
}
|
||||
|
||||
export function DungeonWorldObjects({
|
||||
definitions,
|
||||
}: {
|
||||
readonly definitions: readonly DungeonWorldObjectDefinition[];
|
||||
}) {
|
||||
useSyncExternalStore(
|
||||
subscribeDungeonEncounterSnapshots,
|
||||
activeDungeonEncounterRevision,
|
||||
activeDungeonEncounterRevision,
|
||||
);
|
||||
const states = activeDungeonWorldObjectStates();
|
||||
return (
|
||||
<group name="dungeon-world-objects">
|
||||
{definitions.map((definition) => (
|
||||
<WorldObject key={definition.id} definition={definition} stateId={states[definition.id]} />
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user