ui/scene: clean up initBase

This commit is contained in:
Johannes Kirschbauer
2025-07-19 14:40:32 +02:00
parent c181400267
commit 2d937b80b1

View File

@@ -71,7 +71,6 @@ export function CubeScene(props: {
setMachinePos: (machineId: string, pos: [number, number]) => void; setMachinePos: (machineId: string, pos: [number, number]) => void;
isLoading: boolean; isLoading: boolean;
}) { }) {
// sceneData.cubesQuer
let container: HTMLDivElement; let container: HTMLDivElement;
let scene: THREE.Scene; let scene: THREE.Scene;
let camera: THREE.PerspectiveCamera; let camera: THREE.PerspectiveCamera;
@@ -80,6 +79,7 @@ export function CubeScene(props: {
let controls: MapControls; let controls: MapControls;
// Raycaster for clicking // Raycaster for clicking
const raycaster = new THREE.Raycaster(); const raycaster = new THREE.Raycaster();
let initBase: THREE.Mesh | undefined;
let needsRender = false; // Flag to control rendering let needsRender = false; // Flag to control rendering
@@ -172,6 +172,7 @@ export function CubeScene(props: {
// Add the machine to the store // Add the machine to the store
// Adding it triggers a reactive update // Adding it triggers a reactive update
props.setMachinePos(id, position); props.setMachinePos(id, position);
occupiedPositions.add(keyFromPos(position));
} }
} }
}); });
@@ -184,7 +185,12 @@ export function CubeScene(props: {
} }
function renderScene() { function renderScene() {
if (!isAnimating) return; if (!isAnimating) {
console.warn("Not animating!");
return;
}
console.log("Rendering scene...", initBase.position);
needsRender = false; needsRender = false;
frameCount++; frameCount++;
@@ -222,7 +228,6 @@ export function CubeScene(props: {
const key = keyFromPos(pos); const key = keyFromPos(pos);
if (!occupiedPositions.has(key)) { if (!occupiedPositions.has(key)) {
occupiedPositions.add(key);
return pos; return pos;
} }
} }
@@ -451,8 +456,6 @@ export function CubeScene(props: {
), ),
); );
let initBase: THREE.Mesh;
const grid = new THREE.GridHelper(1000, 1000 / 1, 0xe1edef, 0xe1edef); const grid = new THREE.GridHelper(1000, 1000 / 1, 0xe1edef, 0xe1edef);
onMount(() => { onMount(() => {
@@ -589,6 +592,16 @@ export function CubeScene(props: {
BASE_SIZE, BASE_SIZE,
); );
// Important create CubeBase depends on sharedBaseGeometry
initBase = createCubeBase(
[1, BASE_HEIGHT / 2, 1],
1,
CREATE_BASE_COLOR,
CREATE_BASE_EMISSIVE,
);
scene.add(initBase);
// const spherical = new THREE.Spherical(); // const spherical = new THREE.Spherical();
// spherical.setFromVector3(camera.position); // spherical.setFromVector3(camera.position);
@@ -618,18 +631,14 @@ export function CubeScene(props: {
// - Creates a new cube in "create" mode // - Creates a new cube in "create" mode
const onClick = (event: MouseEvent) => { const onClick = (event: MouseEvent) => {
if (worldMode() === "create") { if (worldMode() === "create") {
if (initBase) { setWorldMode("view");
scene.remove(initBase); // Remove the base mesh after adding cube
setWorldMode("view");
// res.result.then(() => { // res.result.then(() => {
// props.cubesQuery.refetch(); // props.cubesQuery.refetch();
// positionMap.set("sara", pos); // positionMap.set("sara", pos);
// addCube("sara"); // addCube("sara");
// }); // });
}
return;
} }
const rect = renderer.domElement.getBoundingClientRect(); const rect = renderer.domElement.getBoundingClientRect();
@@ -673,6 +682,8 @@ export function CubeScene(props: {
requestRenderIfNotRequested(); requestRenderIfNotRequested();
}; };
renderer.domElement.addEventListener("mousemove", onMouseMove);
window.addEventListener("resize", handleResize); window.addEventListener("resize", handleResize);
// For debugging, // For debugging,
// TODO: Remove in production // TODO: Remove in production
@@ -689,6 +700,7 @@ export function CubeScene(props: {
// Stop animation loop // Stop animation loop
isAnimating = false; isAnimating = false;
renderer.domElement.removeEventListener("click", onClick); renderer.domElement.removeEventListener("click", onClick);
renderer.domElement.removeEventListener("mousemove", onMouseMove);
window.removeEventListener("resize", handleResize); window.removeEventListener("resize", handleResize);
if (initBase) { if (initBase) {
@@ -841,38 +853,60 @@ export function CubeScene(props: {
}); });
const onHover = (inside: boolean) => (event: MouseEvent) => { const onHover = (inside: boolean) => (event: MouseEvent) => {
// Hover over the plus button, shows a preview of the base mesh const pos = nextGridPos();
const currentCubes = cubes(); if (!initBase) return;
if (currentCubes.length > 0) {
return;
}
if (!initBase) { initBase.position.set(pos[0], BASE_HEIGHT / 2, pos[1]);
// Create initial base mesh if it doesn't exist
initBase = createCubeBase( requestRenderIfNotRequested();
[0, BASE_HEIGHT / 2, 0],
1,
CREATE_BASE_COLOR,
CREATE_BASE_EMISSIVE,
); // Emissive color
}
if (inside) {
scene.add(initBase);
} else {
scene.remove(initBase);
}
}; };
const onAddClick = (event: MouseEvent) => { const onAddClick = (event: MouseEvent) => {
setPositionMode("grid"); setPositionMode("grid");
setWorldMode("create"); setWorldMode("create");
}; };
const onMouseMove = (event: MouseEvent) => {
if (worldMode() !== "create") return;
const rect = renderer.domElement.getBoundingClientRect();
const mouse = new THREE.Vector2(
((event.clientX - rect.left) / rect.width) * 2 - 1,
-((event.clientY - rect.top) / rect.height) * 2 + 1,
);
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(floor);
if (intersects.length > 0) {
const point = intersects[0].point;
// Snap to grid
const snapped = new THREE.Vector3(
Math.round(point.x / GRID_SIZE) * GRID_SIZE,
0,
Math.round(point.z / GRID_SIZE) * GRID_SIZE,
);
if (
Math.abs(initBase.position.x - snapped.x) > 0.01 ||
Math.abs(initBase.position.z - snapped.z) > 0.01
) {
// Only request render if the position actually changed
initBase.position.set(snapped.x, 0, snapped.z);
setCursorPosition([snapped.x, snapped.z]); // Update next position for cube creation
requestRenderIfNotRequested();
}
}
};
return ( return (
<> <>
<div class="cubes-scene-container" ref={(el) => (container = el)} /> <div class="cubes-scene-container" ref={(el) => (container = el)} />
<div class="toolbar-container"> <div class="toolbar-container">
<Toolbar> <Toolbar>
<ToolbarButton
name="Select"
icon="Cursor"
onClick={() => setWorldMode("view")}
selected={worldMode() === "view"}
/>
<ToolbarButton <ToolbarButton
name="new-machine" name="new-machine"
icon="NewMachine" icon="NewMachine"