feat: Refactor conveyor collider logic, enhance material spawning, and remove unused colliders component
This commit is contained in:
@@ -13,7 +13,6 @@ function ConveyorCollider({ boundingBox, asset, conveyorPlaneSize, onReachEnd }:
|
|||||||
const [objectsOnConveyor, setObjectsOnConveyor] = useState<Set<any>>(new Set());
|
const [objectsOnConveyor, setObjectsOnConveyor] = useState<Set<any>>(new Set());
|
||||||
const conveyorDirection = useRef<THREE.Vector3>(new THREE.Vector3());
|
const conveyorDirection = useRef<THREE.Vector3>(new THREE.Vector3());
|
||||||
const conveyorSpeed = 2;
|
const conveyorSpeed = 2;
|
||||||
const reached = useRef<Set<RapierRigidBody>>(new Set());
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!boundingBox || !conveyorPlaneSize) return;
|
if (!boundingBox || !conveyorPlaneSize) return;
|
||||||
@@ -49,72 +48,67 @@ function ConveyorCollider({ boundingBox, asset, conveyorPlaneSize, onReachEnd }:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// useFrame(() => {
|
useFrame(() => {
|
||||||
// const forward = conveyorDirection.current.clone().normalize();
|
const forward = conveyorDirection.current.clone().normalize();
|
||||||
// const side = new THREE.Vector3().crossVectors(forward, new THREE.Vector3(0, 1, 0)).normalize(); // perpendicular vector
|
const side = new THREE.Vector3().crossVectors(forward, new THREE.Vector3(0, 1, 0)).normalize();
|
||||||
|
|
||||||
|
const force = forward.clone().multiplyScalar(conveyorSpeed);
|
||||||
|
|
||||||
|
objectsOnConveyor.forEach(rigidBody => {
|
||||||
|
if (rigidBody) {
|
||||||
|
const position = rigidBody.translation();
|
||||||
|
|
||||||
|
const centerLine = conveyorRef.current.translation();
|
||||||
|
const relative = new THREE.Vector3().subVectors(position, centerLine);
|
||||||
|
const sideOffset = relative.dot(side);
|
||||||
|
|
||||||
|
const centeringStrength = 10;
|
||||||
|
const centeringForce = side.clone().multiplyScalar(-sideOffset * centeringStrength);
|
||||||
|
|
||||||
|
const totalForce = force.clone().add(centeringForce);
|
||||||
|
|
||||||
|
rigidBody.setAngvel(new THREE.Vector3(0, 0, 0), true);
|
||||||
|
rigidBody.setLinvel(totalForce, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// useFrame(() => {
|
||||||
|
// if (
|
||||||
|
// !boundingBox ||
|
||||||
|
// !conveyorPlaneSize ||
|
||||||
|
// !conveyorRef.current ||
|
||||||
|
// typeof conveyorRef.current.translation !== 'function'
|
||||||
|
// ) return;
|
||||||
|
|
||||||
|
// const forward = conveyorDirection.current.clone().normalize();
|
||||||
|
// const side = new THREE.Vector3().crossVectors(forward, new THREE.Vector3(0, 1, 0)).normalize();
|
||||||
// const force = forward.clone().multiplyScalar(conveyorSpeed);
|
// const force = forward.clone().multiplyScalar(conveyorSpeed);
|
||||||
|
// const start = conveyorRef.current.translation();
|
||||||
|
// const conveyorLength = Math.max(conveyorPlaneSize[0], conveyorPlaneSize[1]);
|
||||||
|
// const halfLength = conveyorLength / 2;
|
||||||
|
|
||||||
// objectsOnConveyor.forEach(rigidBody => {
|
// objectsOnConveyor.forEach(rigidBody => {
|
||||||
// if (rigidBody) {
|
// if (!rigidBody) return;
|
||||||
// const position = rigidBody.translation();
|
|
||||||
|
|
||||||
// const centerLine = conveyorRef.current.translation();
|
// const position = rigidBody.translation();
|
||||||
// const relative = new THREE.Vector3().subVectors(position, centerLine);
|
// const relative = new THREE.Vector3().subVectors(position, start);
|
||||||
// const sideOffset = relative.dot(side);
|
// const forwardOffset = relative.dot(forward);
|
||||||
|
// const sideOffset = relative.dot(side);
|
||||||
|
// const atEnd = forwardOffset >= halfLength - 0.5;
|
||||||
|
|
||||||
|
// if (!atEnd) {
|
||||||
// const centeringStrength = 10;
|
// const centeringStrength = 10;
|
||||||
// const centeringForce = side.clone().multiplyScalar(-sideOffset * centeringStrength);
|
// const centeringForce = side.clone().multiplyScalar(-sideOffset * centeringStrength);
|
||||||
|
|
||||||
// const totalForce = force.clone().add(centeringForce);
|
// const totalForce = force.clone().add(centeringForce);
|
||||||
|
|
||||||
// rigidBody.setAngvel(new THREE.Vector3(0, 0, 0), true);
|
// rigidBody.setAngvel(new THREE.Vector3(0, 0, 0), true);
|
||||||
// rigidBody.setLinvel(totalForce, true);
|
// rigidBody.setLinvel(totalForce, true);
|
||||||
|
// } else {
|
||||||
|
// rigidBody.setLinvel(new THREE.Vector3(0, 0, 0), true);
|
||||||
|
// rigidBody.setAngvel(new THREE.Vector3(0, 0, 0), true);
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
useFrame(() => {
|
|
||||||
if (
|
|
||||||
!boundingBox ||
|
|
||||||
!conveyorPlaneSize ||
|
|
||||||
!conveyorRef.current ||
|
|
||||||
typeof conveyorRef.current.translation !== 'function'
|
|
||||||
) return;
|
|
||||||
|
|
||||||
const forward = conveyorDirection.current.clone().normalize();
|
|
||||||
const side = new THREE.Vector3().crossVectors(forward, new THREE.Vector3(0, 1, 0)).normalize();
|
|
||||||
const force = forward.clone().multiplyScalar(conveyorSpeed);
|
|
||||||
const start = conveyorRef.current.translation();
|
|
||||||
const conveyorLength = Math.max(conveyorPlaneSize[0], conveyorPlaneSize[1]);
|
|
||||||
const halfLength = conveyorLength / 2;
|
|
||||||
|
|
||||||
objectsOnConveyor.forEach(rigidBody => {
|
|
||||||
if (!rigidBody) return;
|
|
||||||
|
|
||||||
const position = rigidBody.translation();
|
|
||||||
const relative = new THREE.Vector3().subVectors(position, start);
|
|
||||||
const forwardOffset = relative.dot(forward);
|
|
||||||
const sideOffset = relative.dot(side);
|
|
||||||
const atEnd = forwardOffset >= halfLength - 0.5;
|
|
||||||
|
|
||||||
if (!atEnd) {
|
|
||||||
const centeringStrength = 10;
|
|
||||||
const centeringForce = side.clone().multiplyScalar(-sideOffset * centeringStrength);
|
|
||||||
const totalForce = force.clone().add(centeringForce);
|
|
||||||
rigidBody.setAngvel(new THREE.Vector3(0, 0, 0), true);
|
|
||||||
rigidBody.setLinvel(totalForce, true);
|
|
||||||
} else {
|
|
||||||
rigidBody.setLinvel(new THREE.Vector3(0, 0, 0), true);
|
|
||||||
rigidBody.setAngvel(new THREE.Vector3(0, 0, 0), true);
|
|
||||||
|
|
||||||
if (!reached.current.has(rigidBody)) {
|
|
||||||
reached.current.add(rigidBody);
|
|
||||||
console.log("✅ Triggering spawn from conveyor");
|
|
||||||
onReachEnd?.(rigidBody); // ✅ trigger here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -111,6 +111,11 @@ const CopyPasteControls = ({
|
|||||||
const copySelection = () => {
|
const copySelection = () => {
|
||||||
if (selectedAssets.length > 0) {
|
if (selectedAssets.length > 0) {
|
||||||
const newClones = selectedAssets.map((asset: any) => {
|
const newClones = selectedAssets.map((asset: any) => {
|
||||||
|
if (asset.userData.rigidBodyRef) {
|
||||||
|
let userData = { ...asset.userData };
|
||||||
|
delete userData.rigidBodyRef;
|
||||||
|
asset.userData = userData;
|
||||||
|
}
|
||||||
const clone = SkeletonUtils.clone(asset);
|
const clone = SkeletonUtils.clone(asset);
|
||||||
clone.position.copy(asset.position);
|
clone.position.copy(asset.position);
|
||||||
return clone;
|
return clone;
|
||||||
|
|||||||
@@ -106,6 +106,11 @@ const DuplicationControls = ({
|
|||||||
const duplicateSelection = () => {
|
const duplicateSelection = () => {
|
||||||
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
||||||
const newClones = selectedAssets.map((asset: any) => {
|
const newClones = selectedAssets.map((asset: any) => {
|
||||||
|
if (asset.userData.rigidBodyRef) {
|
||||||
|
let userData = { ...asset.userData };
|
||||||
|
delete userData.rigidBodyRef;
|
||||||
|
asset.userData = userData;
|
||||||
|
}
|
||||||
const clone = SkeletonUtils.clone(asset);
|
const clone = SkeletonUtils.clone(asset);
|
||||||
clone.position.copy(asset.position);
|
clone.position.copy(asset.position);
|
||||||
return clone;
|
return clone;
|
||||||
|
|||||||
@@ -25,18 +25,26 @@ const Ground = ({ plane }: any) => {
|
|||||||
<RigidBody
|
<RigidBody
|
||||||
type="fixed"
|
type="fixed"
|
||||||
colliders='cuboid'
|
colliders='cuboid'
|
||||||
|
includeInvisible
|
||||||
>
|
>
|
||||||
<mesh
|
<mesh
|
||||||
ref={plane}
|
|
||||||
rotation-x={CONSTANTS.planeConfig.rotation}
|
rotation-x={CONSTANTS.planeConfig.rotation}
|
||||||
position={!toggleView ? CONSTANTS.planeConfig.position3D : CONSTANTS.planeConfig.position2D}
|
position={[0, 0, 0]}
|
||||||
name="Plane"
|
visible={false}
|
||||||
receiveShadow
|
|
||||||
>
|
>
|
||||||
<planeGeometry args={[planeValue.width, planeValue.height]} />
|
<planeGeometry args={[planeValue.width, planeValue.height]} />
|
||||||
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
|
|
||||||
</mesh>
|
</mesh>
|
||||||
</RigidBody>
|
</RigidBody>
|
||||||
|
<mesh
|
||||||
|
ref={plane}
|
||||||
|
rotation-x={CONSTANTS.planeConfig.rotation}
|
||||||
|
position={!toggleView ? CONSTANTS.planeConfig.position3D : CONSTANTS.planeConfig.position2D}
|
||||||
|
name="Plane"
|
||||||
|
receiveShadow
|
||||||
|
>
|
||||||
|
<planeGeometry args={[planeValue.width, planeValue.height]} />
|
||||||
|
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
|
||||||
|
</mesh>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
// import { RigidBody, RapierRigidBody } from '@react-three/rapier'
|
|
||||||
// import { useRef } from 'react';
|
|
||||||
// import { useLoadingProgress } from '../../../store/builder/store'
|
|
||||||
// import { MaterialModel } from '../../simulation/materials/instances/material/materialModel';
|
|
||||||
|
|
||||||
// function Colliders() {
|
|
||||||
// const { loadingProgress } = useLoadingProgress();
|
|
||||||
// const rigidBodyRef = useRef<RapierRigidBody>(null);
|
|
||||||
|
|
||||||
// const handleSleep = () => {
|
|
||||||
// console.log("slept");
|
|
||||||
// const body = rigidBodyRef.current;
|
|
||||||
// if (body) {
|
|
||||||
// body.setTranslation({ x: 0, y: 10, z: 0 }, true);
|
|
||||||
// body.setLinvel({ x: 0, y: 0, z: 0 }, true);
|
|
||||||
// body.setAngvel({ x: 0, y: 0, z: 0 }, true);
|
|
||||||
// body.wakeUp();
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <>
|
|
||||||
// {loadingProgress === 0 && (
|
|
||||||
// <RigidBody
|
|
||||||
// ref={rigidBodyRef}
|
|
||||||
// position={[0, 10, 0]}
|
|
||||||
// colliders="cuboid"
|
|
||||||
// angularDamping={5}
|
|
||||||
// linearDamping={1}
|
|
||||||
// restitution={0.1}
|
|
||||||
// onSleep={handleSleep}
|
|
||||||
// >
|
|
||||||
// <MaterialModel materialId='123' materialType={"Default material"} />
|
|
||||||
// </RigidBody>
|
|
||||||
// )}
|
|
||||||
// </>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export default Colliders;
|
|
||||||
|
|
||||||
|
|
||||||
import { RigidBody, RapierRigidBody } from '@react-three/rapier';
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
|
||||||
import { useLoadingProgress } from '../../../store/builder/store';
|
|
||||||
import { MaterialModel } from '../../simulation/materials/instances/material/materialModel';
|
|
||||||
import { generateUniqueId } from '../../../functions/generateUniqueId';
|
|
||||||
import { useFrame } from '@react-three/fiber';
|
|
||||||
|
|
||||||
type MaterialInstance = {
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function Colliders() {
|
|
||||||
const { loadingProgress } = useLoadingProgress();
|
|
||||||
const [materials, setMaterials] = useState<MaterialInstance[]>([]);
|
|
||||||
|
|
||||||
const spawnNewMaterial = () => {
|
|
||||||
setMaterials(prev => [...prev, { id: generateUniqueId() }]);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (loadingProgress === 0 && materials.length === 0) {
|
|
||||||
spawnNewMaterial(); // spawn one initially
|
|
||||||
}
|
|
||||||
}, [loadingProgress]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{materials.map((mat) => (
|
|
||||||
<SingleMaterial
|
|
||||||
key={mat.id}
|
|
||||||
onReachEnd={spawnNewMaterial}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default Colliders;
|
|
||||||
|
|
||||||
function SingleMaterial({ onReachEnd }: { onReachEnd: () => void }) {
|
|
||||||
const rigidBodyRef = useRef<RapierRigidBody>(null);
|
|
||||||
const hasReachedEnd = useRef(false);
|
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
const body = rigidBodyRef.current;
|
|
||||||
if (!body || hasReachedEnd.current) return;
|
|
||||||
|
|
||||||
const position = body.translation();
|
|
||||||
if (position && position.z > 5) {
|
|
||||||
console.log('✅ Reached end — triggering spawn');
|
|
||||||
hasReachedEnd.current = true;
|
|
||||||
body.setLinvel({ x: 0, y: 0, z: 0 }, true);
|
|
||||||
body.setAngvel({ x: 0, y: 0, z: 0 }, true);
|
|
||||||
onReachEnd();
|
|
||||||
body.setTranslation({ x: 0, y: -100, z: 0 }, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RigidBody
|
|
||||||
ref={rigidBodyRef}
|
|
||||||
position={[0, 10, 0]}
|
|
||||||
colliders="cuboid"
|
|
||||||
angularDamping={5}
|
|
||||||
linearDamping={1}
|
|
||||||
restitution={0.1}
|
|
||||||
>
|
|
||||||
<MaterialModel materialId='123' materialType='Default material' />
|
|
||||||
</RigidBody>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
194
app/src/modules/scene/physics/materialSpawner.tsx
Normal file
194
app/src/modules/scene/physics/materialSpawner.tsx
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
import { RigidBody, RapierRigidBody } from '@react-three/rapier';
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
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';
|
||||||
|
|
||||||
|
type MaterialSpawnerProps = {
|
||||||
|
position: [number, number, number];
|
||||||
|
spawnInterval: number;
|
||||||
|
spawnCount?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function MaterialSpawner({ position, spawnInterval, spawnCount }: MaterialSpawnerProps) {
|
||||||
|
const { loadingProgress } = useLoadingProgress();
|
||||||
|
const [spawned, setSpawned] = useState<{ id: string; position: [number, number, number]; ref: React.RefObject<RapierRigidBody> }[]>([]);
|
||||||
|
const spawnedCount = useRef(0);
|
||||||
|
const { gl, camera, pointer, controls } = useThree();
|
||||||
|
const [draggedId, setDraggedId] = useState<string | null>(null);
|
||||||
|
const dragOffset = useRef<THREE.Vector3>(new THREE.Vector3());
|
||||||
|
const initialDepth = useRef<number>(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loadingProgress !== 0) return;
|
||||||
|
|
||||||
|
let interval: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
|
const startSpawning = () => {
|
||||||
|
if (!interval) {
|
||||||
|
interval = setInterval(() => {
|
||||||
|
setSpawned(prev => {
|
||||||
|
if (spawnCount !== undefined && spawnedCount.current >= spawnCount) {
|
||||||
|
clearInterval(interval!);
|
||||||
|
interval = null;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
spawnedCount.current++;
|
||||||
|
return [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
position,
|
||||||
|
ref: React.createRef<RapierRigidBody>(),
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}, spawnInterval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopSpawning = () => {
|
||||||
|
if (interval) {
|
||||||
|
clearInterval(interval);
|
||||||
|
interval = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleVisibility = () => {
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
startSpawning();
|
||||||
|
} else {
|
||||||
|
stopSpawning();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('visibilitychange', handleVisibility);
|
||||||
|
handleVisibility();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
stopSpawning();
|
||||||
|
document.removeEventListener('visibilitychange', handleVisibility);
|
||||||
|
};
|
||||||
|
}, [loadingProgress, spawnInterval, spawnCount, position]);
|
||||||
|
|
||||||
|
const handleSleep = (id: string) => {
|
||||||
|
setSpawned(prev => prev.filter(obj => obj.id !== id));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePointerDown = (id: string) => {
|
||||||
|
if (controls) {
|
||||||
|
(controls as CameraControls).enabled = false;
|
||||||
|
}
|
||||||
|
setDraggedId(id);
|
||||||
|
|
||||||
|
const obj = spawned.find(o => o.id === id);
|
||||||
|
if (!obj || !obj.ref.current) return;
|
||||||
|
|
||||||
|
const currentPosition = obj.ref.current.translation();
|
||||||
|
|
||||||
|
const screenPosition = new THREE.Vector3(currentPosition.x, currentPosition.y, currentPosition.z).project(camera);
|
||||||
|
|
||||||
|
dragOffset.current = new THREE.Vector3(
|
||||||
|
screenPosition.x - pointer.x,
|
||||||
|
0,
|
||||||
|
screenPosition.y - pointer.y
|
||||||
|
);
|
||||||
|
|
||||||
|
initialDepth.current = new THREE.Vector3(currentPosition.x, currentPosition.y, currentPosition.z)
|
||||||
|
.sub(camera.position)
|
||||||
|
.length();
|
||||||
|
|
||||||
|
obj.ref.current.setGravityScale(0, true);
|
||||||
|
obj.ref.current.setLinearDamping(10);
|
||||||
|
obj.ref.current.setAngularDamping(10);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePointerMove = () => {
|
||||||
|
if (!draggedId) return;
|
||||||
|
|
||||||
|
const obj = spawned.find(o => o.id === draggedId);
|
||||||
|
if (!obj || !obj.ref.current) return;
|
||||||
|
|
||||||
|
const targetScreenPos = new THREE.Vector3(
|
||||||
|
pointer.x + dragOffset.current.x,
|
||||||
|
0,
|
||||||
|
pointer.y + dragOffset.current.z
|
||||||
|
);
|
||||||
|
|
||||||
|
const targetWorldPos = new THREE.Vector3(
|
||||||
|
targetScreenPos.x,
|
||||||
|
targetScreenPos.z,
|
||||||
|
0.5
|
||||||
|
).unproject(camera);
|
||||||
|
|
||||||
|
const direction = targetWorldPos.sub(camera.position).normalize();
|
||||||
|
const finalPosition = camera.position.clone().add(direction.multiplyScalar(initialDepth.current));
|
||||||
|
|
||||||
|
const currentPosition = obj.ref.current.translation();
|
||||||
|
|
||||||
|
const moveDirection = new THREE.Vector3().subVectors(finalPosition, currentPosition);
|
||||||
|
|
||||||
|
obj.ref.current.setLinvel({
|
||||||
|
x: moveDirection.x * 20,
|
||||||
|
y: moveDirection.y * 20,
|
||||||
|
z: moveDirection.z * 20
|
||||||
|
}, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePointerUp = () => {
|
||||||
|
if (controls) {
|
||||||
|
(controls as CameraControls).enabled = true;
|
||||||
|
}
|
||||||
|
if (!draggedId) return;
|
||||||
|
|
||||||
|
const obj = spawned.find(o => o.id === draggedId);
|
||||||
|
if (obj?.ref.current) {
|
||||||
|
obj.ref.current.setGravityScale(1, true);
|
||||||
|
obj.ref.current.setLinearDamping(0.5);
|
||||||
|
obj.ref.current.setAngularDamping(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
setDraggedId(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
canvasElement.addEventListener('pointermove', handlePointerMove);
|
||||||
|
canvasElement.addEventListener('pointerup', handlePointerUp);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener('pointermove', handlePointerMove);
|
||||||
|
canvasElement.removeEventListener('pointerup', handlePointerUp);
|
||||||
|
};
|
||||||
|
}, [draggedId, spawned, controls, camera, gl]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{spawned.map(({ id, position, ref }) => (
|
||||||
|
<RigidBody
|
||||||
|
key={id}
|
||||||
|
ref={ref}
|
||||||
|
position={position}
|
||||||
|
colliders="cuboid"
|
||||||
|
angularDamping={0.5}
|
||||||
|
linearDamping={0.5}
|
||||||
|
restitution={0.1}
|
||||||
|
// onSleep={() => handleSleep(id)}
|
||||||
|
>
|
||||||
|
<MaterialModel
|
||||||
|
materialId={id}
|
||||||
|
materialType="Default material"
|
||||||
|
onPointerDown={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</RigidBody>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MaterialSpawner;
|
||||||
@@ -15,7 +15,7 @@ import { getUserData } from "../../functions/getUserData";
|
|||||||
import { useLoadingProgress, useSocketStore } from "../../store/builder/store";
|
import { useLoadingProgress, useSocketStore } from "../../store/builder/store";
|
||||||
import { Color } from "three";
|
import { Color } from "three";
|
||||||
import { Physics } from "@react-three/rapier";
|
import { Physics } from "@react-three/rapier";
|
||||||
import Colliders from "./physics/colliders";
|
import MaterialSpawner from "./physics/materialSpawner";
|
||||||
|
|
||||||
export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Comparison Layout' }) {
|
export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Comparison Layout' }) {
|
||||||
const map = useMemo(() => [
|
const map = useMemo(() => [
|
||||||
@@ -73,11 +73,20 @@ export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Co
|
|||||||
>
|
>
|
||||||
<Setup />
|
<Setup />
|
||||||
<Collaboration />
|
<Collaboration />
|
||||||
<Physics gravity={[0, -9.81, 0]} debug >
|
<Physics gravity={[0, -9.81, 0]} allowedLinearError={20} numSolverIterations={20} debug >
|
||||||
<Builder />
|
<Builder />
|
||||||
<Simulation />
|
<Simulation />
|
||||||
|
|
||||||
<Colliders />
|
<MaterialSpawner
|
||||||
|
position={[0, 3, 0]}
|
||||||
|
spawnInterval={1000}
|
||||||
|
spawnCount={50}
|
||||||
|
/>
|
||||||
|
<MaterialSpawner
|
||||||
|
position={[-21, 3, -8]}
|
||||||
|
spawnInterval={1000}
|
||||||
|
spawnCount={50}
|
||||||
|
/>
|
||||||
</Physics>
|
</Physics>
|
||||||
<Visualization />
|
<Visualization />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|||||||
Reference in New Issue
Block a user