CameraController.jsx
1 import React, { useRef, useEffect } from 'react'; 2 import { useThree, useFrame } from '@react-three/fiber'; 3 import * as THREE from 'three'; 4 import gsap from 'gsap'; 5 6 const CameraController = ({ onResetCamera }) => { 7 const { camera } = useThree(); 8 const moveSpeed = 1; 9 const rotateSpeed = 0.002; 10 let isDragging = useRef(false); 11 let previousMousePosition = useRef({ x: 0, y: 0 }); 12 13 const resetCamera = () => { 14 gsap.to(camera.position, { 15 x: 0, 16 y: 0, 17 z: 50, 18 duration: 2, 19 ease: "power2.inOut" 20 }); 21 gsap.to(camera.rotation, { 22 x: 0, 23 y: 0, 24 z: 0, 25 duration: 2, 26 ease: "power2.inOut" 27 }); 28 }; 29 30 useEffect(() => { 31 // Initial camera setup 32 camera.position.set(0, 0, 50); 33 camera.lookAt(0, 0, 0); 34 }, [camera]); 35 36 useEffect(() => { 37 if (onResetCamera) { 38 onResetCamera(resetCamera); 39 } 40 }, [onResetCamera]); 41 42 const moveState = useRef({ 43 forward: false, 44 backward: false, 45 left: false, 46 right: false, 47 up: false, 48 down: false, 49 tiltLeft: false, 50 tiltRight: false, 51 }); 52 53 useFrame(() => { 54 const moveVector = new THREE.Vector3(); 55 56 if (moveState.current.forward) moveVector.z -= moveSpeed; 57 if (moveState.current.backward) moveVector.z += moveSpeed; 58 if (moveState.current.left) moveVector.x -= moveSpeed; 59 if (moveState.current.right) moveVector.x += moveSpeed; 60 if (moveState.current.up) moveVector.y += moveSpeed; 61 if (moveState.current.down) moveVector.y -= moveSpeed; 62 63 camera.translateX(moveVector.x); 64 camera.translateY(moveVector.y); 65 camera.translateZ(moveVector.z); 66 67 const tiltSpeed = 0.02; 68 if (moveState.current.tiltLeft) { 69 camera.rotateZ(tiltSpeed); 70 } 71 if (moveState.current.tiltRight) { 72 camera.rotateZ(-tiltSpeed); 73 } 74 }); 75 76 const onMouseMove = (event) => { 77 if (isDragging.current) { 78 const movementX = event.clientX - previousMousePosition.current.x; 79 const movementY = event.clientY - previousMousePosition.current.y; 80 81 camera.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), movementX * rotateSpeed); 82 camera.rotateX(movementY * rotateSpeed); 83 camera.up.set(0, 1, 0); 84 85 previousMousePosition.current = { x: event.clientX, y: event.clientY }; 86 } 87 }; 88 89 const onMouseDown = (event) => { 90 if (event.button === 0) { 91 isDragging.current = true; 92 previousMousePosition.current = { x: event.clientX, y: event.clientY }; 93 } 94 }; 95 96 const onMouseUp = (event) => { 97 if (event.button === 0) { 98 isDragging.current = false; 99 } 100 }; 101 102 const onKeyDown = (event) => { 103 switch (event.key.toLowerCase()) { 104 case 'w': moveState.current.forward = true; break; 105 case 's': moveState.current.backward = true; break; 106 case 'a': moveState.current.left = true; break; 107 case 'd': moveState.current.right = true; break; 108 case ' ': moveState.current.up = true; break; 109 case 'shift': moveState.current.down = true; break; 110 case 'q': moveState.current.tiltLeft = true; break; 111 case 'e': moveState.current.tiltRight = true; break; 112 } 113 }; 114 115 const onKeyUp = (event) => { 116 switch (event.key.toLowerCase()) { 117 case 'w': moveState.current.forward = false; break; 118 case 's': moveState.current.backward = false; break; 119 case 'a': moveState.current.left = false; break; 120 case 'd': moveState.current.right = false; break; 121 case ' ': moveState.current.up = false; break; 122 case 'shift': moveState.current.down = false; break; 123 case 'q': moveState.current.tiltLeft = false; break; 124 case 'e': moveState.current.tiltRight = false; break; 125 } 126 }; 127 128 React.useEffect(() => { 129 window.addEventListener('mousemove', onMouseMove); 130 window.addEventListener('mousedown', onMouseDown); 131 window.addEventListener('mouseup', onMouseUp); 132 window.addEventListener('keydown', onKeyDown); 133 window.addEventListener('keyup', onKeyUp); 134 135 return () => { 136 window.removeEventListener('mousemove', onMouseMove); 137 window.removeEventListener('mousedown', onMouseDown); 138 window.removeEventListener('mouseup', onMouseUp); 139 window.removeEventListener('keydown', onKeyDown); 140 window.removeEventListener('keyup', onKeyUp); 141 }; 142 }, []); 143 144 return null; 145 }; 146 147 export default CameraController;