feat: Enhance conveyor collider functionality with direction toggle and visual indicators

This commit is contained in:
2025-08-19 10:19:18 +05:30
parent 361480578a
commit 7794e51d1f
9 changed files with 684 additions and 258 deletions

View File

@@ -4,7 +4,7 @@ import { useLoadingProgress } from '../../../store/builder/store';
import { MaterialModel } from '../../simulation/materials/instances/material/materialModel';
import { useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { CameraControls } from '@react-three/drei';
import { CameraControls, TransformControls } from '@react-three/drei';
import { generateUniqueId } from '../../../functions/generateUniqueId';
type MaterialSpawnerProps = {
@@ -13,7 +13,7 @@ type MaterialSpawnerProps = {
spawnCount: number;
};
function MaterialSpawner({ position, spawnInterval, spawnCount }: MaterialSpawnerProps) {
function MaterialSpawner({ position: initialPos, spawnInterval, spawnCount }: MaterialSpawnerProps) {
const { loadingProgress } = useLoadingProgress();
const [spawned, setSpawned] = useState<{
id: string;
@@ -28,6 +28,9 @@ function MaterialSpawner({ position, spawnInterval, spawnCount }: MaterialSpawne
const dragOffset = useRef<THREE.Vector3>(new THREE.Vector3());
const initialDepth = useRef<number>(0);
const materialTypes = ['Default material', 'Material 1', 'Material 2', 'Material 3'];
const [boxPosition, setBoxPosition] = useState<[number, number, number]>(initialPos);
const spawnerRef = useRef<THREE.Mesh>(null!);
const newPositionRef = useRef<[number, number, number]>([...initialPos]);
useEffect(() => {
if (loadingProgress !== 0) return;
@@ -46,13 +49,16 @@ function MaterialSpawner({ position, spawnInterval, spawnCount }: MaterialSpawne
}
spawnedCount.current++;
const randomMaterialType = materialTypes[Math.floor(Math.random() * materialTypes.length)];
const randomMaterialType =
materialTypes[Math.floor(Math.random() * materialTypes.length)];
console.log('boxPosition: ', boxPosition);
return [
...prev,
{
id: generateUniqueId(),
position,
position: [...boxPosition] as [number, number, number], // use latest position state
ref: React.createRef<RapierRigidBody>(),
materialType: randomMaterialType,
}
@@ -85,7 +91,9 @@ function MaterialSpawner({ position, spawnInterval, spawnCount }: MaterialSpawne
stopSpawning();
document.removeEventListener('visibilitychange', handleVisibility);
};
}, [loadingProgress, spawnInterval, spawnCount, position, spawningPaused]);
}, [loadingProgress, spawnInterval, spawnCount, spawningPaused, boxPosition]);
const handleSleep = (id: string) => {
setSpawned(prev => prev.filter(obj => obj.id !== id));
@@ -180,16 +188,37 @@ function MaterialSpawner({ position, spawnInterval, spawnCount }: MaterialSpawne
const handleBoxContextMenu = () => {
};
return (
<>
<mesh
position={position}
onClick={handleBoxClick}
onContextMenu={handleBoxContextMenu}
<TransformControls
position={boxPosition}
scale={[0.5, 0.5, 0.5]}
onMouseDown={() => {
if (controls) (controls as CameraControls).enabled = false;
}}
onMouseUp={() => {
if (controls) (controls as CameraControls).enabled = true;
setBoxPosition(newPositionRef.current);
}}
onObjectChange={() => {
if (spawnerRef.current) {
const pos = spawnerRef.current.position;
newPositionRef.current = [pos.x, pos.y, pos.z]; // Save latest
}
}}
>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={spawningPaused ? "red" : "white"} transparent opacity={0.2} />
</mesh>
<mesh
ref={spawnerRef}
// position={boxPosition}
onClick={handleBoxClick}
// onContextMenu={handleBoxContextMenu}
>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={spawningPaused ? "red" : "white"} transparent opacity={0.2} />
</mesh>
</TransformControls>
{spawned.map(({ id, position, materialType, ref }) => (
<RigidBody