2025-04-29 08:12:24 +00:00
|
|
|
import { useFrame, useThree } from "@react-three/fiber";
|
|
|
|
import React, { useEffect, useState } from "react";
|
|
|
|
import * as CONSTANTS from "../../../types/world/worldConstants";
|
2025-05-13 12:23:00 +00:00
|
|
|
import { useCamMode, useToggleView } from "../../../store/builder/store";
|
2025-04-29 08:12:24 +00:00
|
|
|
import { useKeyboardControls } from "@react-three/drei";
|
|
|
|
import switchToThirdPerson from "./switchToThirdPerson";
|
|
|
|
import switchToFirstPerson from "./switchToFirstPerson";
|
|
|
|
import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKeys";
|
2025-03-25 12:04:20 +00:00
|
|
|
|
|
|
|
const CamMode: React.FC = () => {
|
2025-04-29 08:12:24 +00:00
|
|
|
const { camMode, setCamMode } = useCamMode();
|
|
|
|
const [, get] = useKeyboardControls();
|
|
|
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
|
|
const state: any = useThree();
|
|
|
|
const { toggleView } = useToggleView();
|
|
|
|
const [isShiftActive, setIsShiftActive] = useState(false);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const handlePointerLockChange = async () => {
|
|
|
|
if (document.pointerLockElement && !toggleView) {
|
|
|
|
// Pointer is locked
|
2025-05-08 08:12:42 +00:00
|
|
|
} else if (camMode === "FirstPerson" && !toggleView) {
|
2025-04-29 08:12:24 +00:00
|
|
|
// Pointer is unlocked
|
2025-05-08 08:12:42 +00:00
|
|
|
setCamMode("ThirdPerson");
|
|
|
|
await switchToThirdPerson(state.controls, state.camera);
|
2025-04-29 08:12:24 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
document.addEventListener("pointerlockchange", handlePointerLockChange);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
document.removeEventListener(
|
|
|
|
"pointerlockchange",
|
|
|
|
handlePointerLockChange
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}, [camMode, toggleView, setCamMode, state.controls, state.camera]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
|
|
if (event.key === "Shift") {
|
|
|
|
setIsShiftActive(true);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleKeyUp = (event: KeyboardEvent) => {
|
|
|
|
if (event.key === "Shift") {
|
|
|
|
setIsShiftActive(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
|
|
window.addEventListener("keyup", handleKeyUp);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
window.removeEventListener("keydown", handleKeyDown);
|
|
|
|
window.removeEventListener("keyup", handleKeyUp);
|
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const handleKeyPress = async (event: KeyboardEvent) => {
|
|
|
|
if (!state.controls) return;
|
|
|
|
|
|
|
|
const keyCombination = detectModifierKeys(event);
|
|
|
|
|
|
|
|
if (keyCombination === "/" && !isTransitioning && !toggleView) {
|
|
|
|
setIsTransitioning(true);
|
|
|
|
|
|
|
|
state.controls.mouseButtons.left =
|
|
|
|
CONSTANTS.controlsTransition.leftMouse;
|
|
|
|
state.controls.mouseButtons.right =
|
|
|
|
CONSTANTS.controlsTransition.rightMouse;
|
|
|
|
state.controls.mouseButtons.wheel =
|
|
|
|
CONSTANTS.controlsTransition.wheelMouse;
|
|
|
|
state.controls.mouseButtons.middle =
|
|
|
|
CONSTANTS.controlsTransition.middleMouse;
|
|
|
|
|
|
|
|
if (camMode === "ThirdPerson") {
|
|
|
|
setCamMode("FirstPerson");
|
|
|
|
await switchToFirstPerson(state.controls, state.camera);
|
|
|
|
} else if (camMode === "FirstPerson") {
|
|
|
|
setCamMode("ThirdPerson");
|
|
|
|
await switchToThirdPerson(state.controls, state.camera);
|
2025-03-25 12:04:20 +00:00
|
|
|
}
|
|
|
|
|
2025-04-29 08:12:24 +00:00
|
|
|
setIsTransitioning(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
window.addEventListener("keydown", handleKeyPress);
|
|
|
|
return () => {
|
|
|
|
window.removeEventListener("keydown", handleKeyPress);
|
|
|
|
};
|
|
|
|
}, [
|
|
|
|
camMode,
|
|
|
|
isTransitioning,
|
|
|
|
toggleView,
|
|
|
|
state.controls,
|
|
|
|
state.camera,
|
|
|
|
setCamMode,
|
|
|
|
]);
|
|
|
|
|
|
|
|
useFrame(() => {
|
|
|
|
const { forward, backward, left, right } = get();
|
|
|
|
if (!state.controls) return;
|
|
|
|
if (camMode === "ThirdPerson" || !document.pointerLockElement) return;
|
|
|
|
|
|
|
|
const speedMultiplier = isShiftActive ? 4 : 1;
|
|
|
|
|
|
|
|
if (forward) {
|
|
|
|
state.controls.forward(
|
|
|
|
CONSTANTS.firstPersonControls.forwardSpeed * speedMultiplier,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (backward) {
|
|
|
|
state.controls.forward(
|
|
|
|
CONSTANTS.firstPersonControls.backwardSpeed * speedMultiplier,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (left) {
|
|
|
|
state.controls.truck(
|
|
|
|
CONSTANTS.firstPersonControls.leftSpeed * speedMultiplier,
|
|
|
|
0,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (right) {
|
|
|
|
state.controls.truck(
|
|
|
|
CONSTANTS.firstPersonControls.rightSpeed * speedMultiplier,
|
|
|
|
0,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return null; // This component does not render any UI
|
2025-03-25 12:04:20 +00:00
|
|
|
};
|
|
|
|
|
2025-04-29 08:12:24 +00:00
|
|
|
export default CamMode;
|