Files
Dwinzo_Demo/app/src/modules/scene/physics/colliders/colliderInstance/colliderArrow.tsx
Gomathi9520 d1c78495ea feat: Implement collider functionality with drag-and-drop arrows and conditions
- Added Collider and ColliderCondition types to manage collider properties.
- Created a new useColliderStore for managing colliders and their arrows.
- Implemented ColliderArrow component for visual representation and interaction of arrows.
- Enhanced ColliderProperties UI for managing directions and conditions.
- Updated PhysicsSimulator and Scene components to integrate collider features.
- Refactored existing code for better organization and clarity.
2025-08-21 17:57:45 +05:30

116 lines
3.9 KiB
TypeScript

import { useRef, useMemo, useState, useCallback } from "react";
import { useThree, useFrame } from "@react-three/fiber";
import * as THREE from "three";
import { useSceneContext } from "../../../sceneContext";
type ColliderArrowProps = {
arrowId: string;
colliderId: string;
startPosition: [number, number, number];
endPosition: [number, number, number];
colliderRotation: [number, number, number];
thickness?: number;
depth?: number;
color?: string;
};
export function ColliderArrow({
arrowId,
colliderId,
startPosition,
endPosition,
colliderRotation,
thickness = 0.05,
depth = 0.01,
color = "green",
}: ColliderArrowProps) {
const groupRef = useRef<THREE.Group>(null);
const { raycaster, pointer, controls } = useThree();
const { colliderStore } = useSceneContext();
const { updateArrow, selectedArrowId, clearSelectedArrow } = colliderStore();
const [dragging, setDragging] = useState(false);
const { dir, length } = useMemo(() => {
const start = new THREE.Vector3(...startPosition);
const end = new THREE.Vector3(...endPosition);
const d = new THREE.Vector3().subVectors(end, start);
return { dir: d.clone().normalize(), length: d.length() };
}, [startPosition, endPosition]);
const arrowShape = useMemo(() => {
const shaftWidth = thickness;
const headLength = Math.min(length * 0.3, 0.4);
const headWidth = thickness * 3;
const shape = new THREE.Shape();
shape.moveTo(0, -shaftWidth / 2);
shape.lineTo(length - headLength, -shaftWidth / 2);
shape.lineTo(length - headLength, -headWidth / 2);
shape.lineTo(length, 0);
shape.lineTo(length - headLength, headWidth / 2);
shape.lineTo(length - headLength, shaftWidth / 2);
shape.lineTo(0, shaftWidth / 2);
shape.closePath();
return shape;
}, [length, thickness]);
const extrudeSettings = useMemo(() => ({ depth, bevelEnabled: false, }), [depth]);
const geometry = useMemo(() => new THREE.ExtrudeGeometry(arrowShape, extrudeSettings), [arrowShape, extrudeSettings]);
const quaternion = useMemo(() => {
const q = new THREE.Quaternion();
q.setFromUnitVectors(new THREE.Vector3(1, 0, 0), dir);
const colliderQuat = new THREE.Quaternion().setFromEuler(
new THREE.Euler().fromArray(colliderRotation)
);
return colliderQuat.multiply(q);
}, [dir, colliderRotation]);
const handlePointerDown = useCallback((e: any) => {
e.stopPropagation();
setDragging(true);
(controls as any).enabled = false; // Disable controls while dragging
}, []);
const handlePointerUp = useCallback((e: any) => {
e.stopPropagation();
clearSelectedArrow()
setDragging(false);
(controls as any).enabled = true;
}, []);
useFrame(({ camera }) => {
if (dragging) {
if (selectedArrowId) {
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), -startPosition[1]);
raycaster.setFromCamera(pointer, camera);
const hit = new THREE.Vector3();
if (raycaster.ray.intersectPlane(plane, hit)) {
updateArrow(colliderId, arrowId, {
position: [hit.x, startPosition[1], hit.z],
});
}
}
}
});
return (
<group ref={groupRef} quaternion={quaternion}>
<mesh geometry={geometry} rotation={[Math.PI / 2, 0, 0]}>
<meshStandardMaterial color={color} />
</mesh>
<mesh
position={[length, 0, 0]}
onPointerDown={handlePointerDown}
onPointerUp={handlePointerUp}
>
<sphereGeometry args={[0.15, 16, 16]} />
<meshBasicMaterial transparent opacity={0.2} color="yellow" />
</mesh>
</group>
);
}