/ src / components / CameraController.jsx
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;