diff --git a/src/components/ebike/Ebike.tsx b/src/components/ebike/Ebike.tsx index 05f13ff..b42fcd2 100644 --- a/src/components/ebike/Ebike.tsx +++ b/src/components/ebike/Ebike.tsx @@ -3,13 +3,27 @@ import * as THREE from "three"; import { InteractableObject } from "@/components/three/interaction/InteractableObject"; import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF"; import { useClonedObject } from "@/hooks/three/useClonedObject"; +import { useDebugFolder } from "@/hooks/debug/useDebugFolder"; import { animateCameraTransition } from "@/world/GameCinematics"; import { useGameStore } from "@/managers/stores/useGameStore"; import type { Vector3Tuple } from "@/types/three/three"; const EBIKE_MODEL_PATH = "/models/ebike/model.gltf"; -const EBIKE_CAMERA_POSITION: Vector3Tuple = [0, 1.5, -2]; -const EBIKE_DROP_PLAYER_POSITION: Vector3Tuple = [2, 0, 0]; + +interface CameraTransform { + position: Vector3Tuple; + rotation: Vector3Tuple; +} + +const EBIKE_CAMERA_TRANSFORM: CameraTransform = { + position: [-3, 8, 0], + rotation: [0, 90, 0], +}; + +const EBIKE_DROP_PLAYER_TRANSFORM: CameraTransform = { + position: [3, 1.5, 0], + rotation: [0, 0, 0], +}; interface EbikeProps { position: Vector3Tuple; @@ -19,17 +33,38 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element { const groupRef = useRef(null); const { scene } = useLoggedGLTF(EBIKE_MODEL_PATH, { scope: "Ebike", - position, + position: [0, 0, 0], }); const model = useClonedObject(scene); const movementMode = useGameStore((state) => state.player.movementMode); + const debugRef = useRef({ showCameraPoints: true }); + useDebugFolder("Ebike", (folder) => { + folder + .add(debugRef.current, "showCameraPoints") + .name("Show Camera Points") + .onChange((value: boolean) => { + debugRef.current.showCameraPoints = value; + }); + }); + + const camPointPos: Vector3Tuple = [ + position[0] + EBIKE_CAMERA_TRANSFORM.position[0], + position[1] + EBIKE_CAMERA_TRANSFORM.position[1], + position[2] + EBIKE_CAMERA_TRANSFORM.position[2], + ]; + const dropPointPos: Vector3Tuple = [ + position[0] + EBIKE_DROP_PLAYER_TRANSFORM.position[0], + position[1] + EBIKE_DROP_PLAYER_TRANSFORM.position[1], + position[2] + EBIKE_DROP_PLAYER_TRANSFORM.position[2], + ]; + const handleInteract = (): void => { if (movementMode === "walk") { const targetCamPos: Vector3Tuple = [ - position[0] + EBIKE_CAMERA_POSITION[0], - position[1] + EBIKE_CAMERA_POSITION[1], - position[2] + EBIKE_CAMERA_POSITION[2], + position[0] + EBIKE_CAMERA_TRANSFORM.position[0], + position[1] + EBIKE_CAMERA_TRANSFORM.position[1], + position[2] + EBIKE_CAMERA_TRANSFORM.position[2], ]; const targetLookAt: Vector3Tuple = [ position[0], @@ -42,9 +77,9 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element { }); } else { const targetCamPos: Vector3Tuple = [ - position[0] + EBIKE_DROP_PLAYER_POSITION[0], - position[1] + EBIKE_DROP_PLAYER_POSITION[1], - position[2] + EBIKE_DROP_PLAYER_POSITION[2], + position[0] + EBIKE_DROP_PLAYER_TRANSFORM.position[0], + position[1] + EBIKE_DROP_PLAYER_TRANSFORM.position[1], + position[2] + EBIKE_DROP_PLAYER_TRANSFORM.position[2], ]; const targetLookAt: Vector3Tuple = [ position[0], @@ -59,7 +94,7 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element { }; return ( - + + {debugRef.current.showCameraPoints && ( + <> + + + + + + + + + + )} ); } diff --git a/src/world/GameCinematics.tsx b/src/world/GameCinematics.tsx index c662986..2464589 100644 --- a/src/world/GameCinematics.tsx +++ b/src/world/GameCinematics.tsx @@ -181,7 +181,7 @@ function playCinematic( let cameraTransitionTimeline: gsap.core.Timeline | null = null; let globalCamera: THREE.Camera | null = null; -export function setGlobalCamera(camera: THREE.Camera): void { +export function setGlobalCamera(camera: THREE.Camera | null): void { globalCamera = camera; } diff --git a/src/world/GameStageContent.tsx b/src/world/GameStageContent.tsx index 1ffe603..e31b163 100644 --- a/src/world/GameStageContent.tsx +++ b/src/world/GameStageContent.tsx @@ -51,14 +51,12 @@ function StageAnchor({ export function GameStageContent(): React.JSX.Element { const mainState = useGameStore((state) => state.mainState); - const isBikeUnlocked = useGameStore((state) => state.intro.isBikeUnlocked); return ( <> {mainState === "intro" ? ( ) : null} - {/* {isBikeUnlocked ? : null} */} {GAME_REPAIR_ZONES.map((zone) => ( state.camera); + useEffect(() => { + setGlobalCamera(camera); return () => { + setGlobalCamera(null); document.exitPointerLock(); }; - }, []); + }, [camera]); return ; } diff --git a/src/world/player/PlayerController.tsx b/src/world/player/PlayerController.tsx index 7e19aea..6ecaa17 100644 --- a/src/world/player/PlayerController.tsx +++ b/src/world/player/PlayerController.tsx @@ -108,6 +108,7 @@ export function PlayerController({ const initializedRef = useRef(false); const canMove = useGameStore((state) => state.missionFlow.canMove); const currentSpeed = useGameStore((state) => state.player.currentSpeed); + const movementMode = useGameStore((state) => state.player.movementMode); const capsule = useRef(createSpawnCapsule(spawnPosition)); @@ -282,7 +283,9 @@ export function PlayerController({ } } - camera.position.copy(capsule.current.end); + if (movementMode !== "ebike") { + camera.position.copy(capsule.current.end); + } }); return null;