diff --git a/src/components/ebike/Ebike.tsx b/src/components/ebike/Ebike.tsx index aedeb57..d9d526e 100644 --- a/src/components/ebike/Ebike.tsx +++ b/src/components/ebike/Ebike.tsx @@ -40,40 +40,67 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element { const model = useClonedObject(scene); const movementMode = useGameStore((state) => state.player.movementMode); + const restingPosition = useRef(position); + const restingRotation = useRef(0); + useEffect(() => { (window as any).ebikeVisualGroup = groupRef; + (window as any).ebikeParkedPosition = restingPosition.current; + (window as any).ebikeParkedRotation = restingRotation.current; return () => { (window as any).ebikeVisualGroup = null; + (window as any).ebikeParkedPosition = null; + (window as any).ebikeParkedRotation = null; }; }, []); useFrame(() => { - if (groupRef.current && movementMode !== "ebike") { - // Reset to original position - groupRef.current.position.set(...position); - groupRef.current.rotation.set(0, 0, 0); + if (groupRef.current) { + if (movementMode === "ebike") { + restingPosition.current = [ + groupRef.current.position.x, + groupRef.current.position.y, + groupRef.current.position.z, + ]; + restingRotation.current = groupRef.current.rotation.y; + } else { + groupRef.current.position.set(...restingPosition.current); + groupRef.current.rotation.set(0, restingRotation.current, 0); + } + (window as any).ebikeParkedPosition = restingPosition.current; + (window as any).ebikeParkedRotation = restingRotation.current; } }); const camPointPos: Vector3Tuple = [ - position[0] + EBIKE_CAMERA_TRANSFORM.position[0], - position[1] + EBIKE_CAMERA_TRANSFORM.position[1], - position[2] + EBIKE_CAMERA_TRANSFORM.position[2], + restingPosition.current[0] + EBIKE_CAMERA_TRANSFORM.position[0], + restingPosition.current[1] + EBIKE_CAMERA_TRANSFORM.position[1], + restingPosition.current[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], + restingPosition.current[0] + EBIKE_DROP_PLAYER_TRANSFORM.position[0], + restingPosition.current[1] + EBIKE_DROP_PLAYER_TRANSFORM.position[1], + restingPosition.current[2] + EBIKE_DROP_PLAYER_TRANSFORM.position[2], ]; const handleInteract = (): void => { if (movementMode === "walk") { + const cameraOffset = new THREE.Vector3(...EBIKE_CAMERA_TRANSFORM.position); + cameraOffset.applyAxisAngle(new THREE.Vector3(0, 1, 0), restingRotation.current); + const targetCamPos: Vector3Tuple = [ - position[0] + EBIKE_CAMERA_TRANSFORM.position[0], - position[1] + EBIKE_CAMERA_TRANSFORM.position[1], - position[2] + EBIKE_CAMERA_TRANSFORM.position[2], + restingPosition.current[0] + cameraOffset.x, + restingPosition.current[1] + cameraOffset.y, + restingPosition.current[2] + cameraOffset.z, ]; - animateCameraTransformTransition(targetCamPos, EBIKE_CAMERA_TRANSFORM.rotation, 1, () => { + + const targetRotation: Vector3Tuple = [ + EBIKE_CAMERA_TRANSFORM.rotation[0], + EBIKE_CAMERA_TRANSFORM.rotation[1] + THREE.MathUtils.radToDeg(restingRotation.current), + EBIKE_CAMERA_TRANSFORM.rotation[2], + ]; + + animateCameraTransformTransition(targetCamPos, targetRotation, 1, () => { useGameStore.getState().setPlayerMovementMode("ebike"); }); } else { diff --git a/src/world/player/PlayerController.tsx b/src/world/player/PlayerController.tsx index 3359000..3b4840d 100644 --- a/src/world/player/PlayerController.tsx +++ b/src/world/player/PlayerController.tsx @@ -117,11 +117,12 @@ export function PlayerController({ useEffect(() => { movementModeRef.current = movementMode; }, [movementMode]); - useEffect(() => { if (movementMode === "ebike") { - // Teleport player capsule to the bike's spawning position [0, 10, 0] - const targetPos: Vector3Tuple = [0, 10, 0]; + // Teleport player capsule to the bike's current parked position + const targetPos: Vector3Tuple = (window as any).ebikeParkedPosition || [0, 10, 0]; + const targetRot: number = (window as any).ebikeParkedRotation || 0; + capsule.current.start.set( targetPos[0], targetPos[1] - PLAYER_EYE_HEIGHT + PLAYER_CAPSULE_RADIUS, @@ -132,16 +133,23 @@ export function PlayerController({ onFloor.current = false; wantsJump.current = false; - // Initialize ebikeAngle to the bike's visual orientation (0 by default) - ebikeAngle.current = 0; + // Initialize ebikeAngle to the bike's actual parked orientation! + ebikeAngle.current = targetRot; + + // Position the camera exactly at the EBIKE_CAMERA_TRANSFORM offset rotated by targetRot + const cameraOffset = new THREE.Vector3(...EBIKE_CAMERA_TRANSFORM.position); + cameraOffset.applyAxisAngle(_up, targetRot); - // Position the camera exactly at the EBIKE_CAMERA_TRANSFORM offset [-3, 8, 0] - const cameraOffset = new THREE.Vector3(-3, 8, 0); const camPos = new THREE.Vector3() .copy(capsule.current.end) .add(cameraOffset); camera.position.copy(camPos); - camera.lookAt(capsule.current.end.x, capsule.current.end.y + 1, capsule.current.end.z); + + // Set the camera's exact rotation according to EBIKE_CAMERA_TRANSFORM.rotation + targetRot + const pitchRad = THREE.MathUtils.degToRad(EBIKE_CAMERA_TRANSFORM.rotation[0]); + const yawRad = THREE.MathUtils.degToRad(EBIKE_CAMERA_TRANSFORM.rotation[1]) + targetRot; + const rollRad = THREE.MathUtils.degToRad(EBIKE_CAMERA_TRANSFORM.rotation[2]); + camera.rotation.set(pitchRad, yawRad, rollRad, "YXZ"); } else if (movementMode === "walk" && prevMovementModeRef.current === "ebike") { // Dismount! Teleport player capsule 3 units to the right const rightDir = new THREE.Vector3();