refactor: Enhance ControlsPlayer and CamMode for improved camera mode handling and UI responsiveness

This commit is contained in:
Vishnu 2025-05-15 12:06:51 +05:30
parent 8facad31bc
commit 9cd08f75e3
6 changed files with 104 additions and 34 deletions

View File

@ -1,23 +1,44 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import useCameraModeStore, {
usePlayButtonStore,
} from "../../../store/usePlayButtonStore";
import useModuleStore from "../../../store/useModuleStore"; import useModuleStore from "../../../store/useModuleStore";
import { PlayIcon } from "../../icons/ShortcutIcons"; import { PlayIcon } from "../../icons/ShortcutIcons";
import InputToggle from "../../ui/inputs/InputToggle"; import InputToggle from "../../ui/inputs/InputToggle";
import { EyeCloseIcon, WalkIcon } from "../../icons/ExportCommonIcons"; import { EyeCloseIcon, WalkIcon } from "../../icons/ExportCommonIcons";
import { ExitIcon } from "../../icons/SimulationIcons"; import { ExitIcon } from "../../icons/SimulationIcons";
import { useCamMode } from "../../../store/builder/store";
const ControlsPlayer = () => { const ControlsPlayer: React.FC = () => {
const { setIsPlaying } = usePlayButtonStore(); const { setIsPlaying } = usePlayButtonStore();
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const [walkMode, setWalkMode] = useState(false); const { walkMode, toggleWalkMode } = useCameraModeStore();
const [hidePlayer, setHidePlayer] = useState(false); const [hidePlayer, setHidePlayer] = useState(false);
const { camMode } = useCamMode();
const changeCamMode = () => { const changeCamMode = () => {
setWalkMode(!walkMode); toggleWalkMode();
console.log("switch camera mode to first person"); echo.log("switch camera mode to first person");
// Simulate "/" keypress
const slashKeyEvent = new KeyboardEvent("keydown", {
key: "/",
code: "Slash",
keyCode: 191, // for compatibility
which: 191,
bubbles: true,
cancelable: true,
});
document.dispatchEvent(slashKeyEvent);
}; };
useEffect(() => {
if (camMode === "ThirdPerson") {
toggleWalkMode();
} else return;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [camMode]);
return ( return (
<div className="controls-player-container"> <div className={`controls-player-container${hidePlayer ? " hide" : ""}`}>
{!hidePlayer && ( {!hidePlayer && (
<div className="controls-left"> <div className="controls-left">
<PlayIcon /> <PlayIcon />
@ -26,7 +47,7 @@ const ControlsPlayer = () => {
)} )}
<div className="controls-right"> <div className="controls-right">
{!hidePlayer && ( {!hidePlayer && activeModule === "builder" && (
<div className="walkMode-wrapper"> <div className="walkMode-wrapper">
<WalkIcon /> <WalkIcon />
<InputToggle <InputToggle

View File

@ -6,6 +6,7 @@ import { useKeyboardControls } from "@react-three/drei";
import switchToThirdPerson from "./switchToThirdPerson"; import switchToThirdPerson from "./switchToThirdPerson";
import switchToFirstPerson from "./switchToFirstPerson"; import switchToFirstPerson from "./switchToFirstPerson";
import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKeys"; import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKeys";
import { firstPersonCamera } from "./firstPersonCamera";
const CamMode: React.FC = () => { const CamMode: React.FC = () => {
const { camMode, setCamMode } = useCamMode(); const { camMode, setCamMode } = useCamMode();
@ -65,26 +66,14 @@ const CamMode: React.FC = () => {
const keyCombination = detectModifierKeys(event); const keyCombination = detectModifierKeys(event);
if (keyCombination === "/" && !isTransitioning && !toggleView) { if (keyCombination === "/" && !isTransitioning && !toggleView) {
setIsTransitioning(true); firstPersonCamera({
setIsTransitioning,
state.controls.mouseButtons.left = state,
CONSTANTS.controlsTransition.leftMouse; camMode,
state.controls.mouseButtons.right = setCamMode,
CONSTANTS.controlsTransition.rightMouse; switchToFirstPerson,
state.controls.mouseButtons.wheel = switchToThirdPerson,
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);
}
setIsTransitioning(false);
} }
}; };
@ -92,6 +81,7 @@ const CamMode: React.FC = () => {
return () => { return () => {
window.removeEventListener("keydown", handleKeyPress); window.removeEventListener("keydown", handleKeyPress);
}; };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
camMode, camMode,
isTransitioning, isTransitioning,
@ -140,6 +130,3 @@ const CamMode: React.FC = () => {
}; };
export default CamMode; export default CamMode;

View File

@ -0,0 +1,39 @@
import * as CONSTANTS from "../../../types/world/worldConstants";
interface FirstPersonCameraProps {
setIsTransitioning?: (value: boolean) => void;
state: any;
}
interface FirstPersonCameraParams extends FirstPersonCameraProps {
camMode: string;
setCamMode: (mode: string) => void;
switchToFirstPerson: (controls: any, camera: any) => Promise<void>;
switchToThirdPerson: (controls: any, camera: any) => Promise<void>;
}
export async function firstPersonCamera({
setIsTransitioning,
state,
camMode,
setCamMode,
switchToFirstPerson,
switchToThirdPerson
}: FirstPersonCameraParams): Promise<void> {
setIsTransitioning && 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);
}
setIsTransitioning && setIsTransitioning(false);
}

View File

@ -33,3 +33,17 @@ export const useAnimationPlaySpeed = create<AnimationSpeedState>((set) => ({
speed: 1, speed: 1,
setSpeed: (value) => set({ speed: value }), setSpeed: (value) => set({ speed: value }),
})); }));
interface CameraModeState {
walkMode: boolean;
setWalkMode: (enabled: boolean) => void;
toggleWalkMode: () => void;
}
const useCameraModeStore = create<CameraModeState>((set) => ({
walkMode: false,
setWalkMode: (enabled) => set({ walkMode: enabled }),
toggleWalkMode: () => set((state) => ({ walkMode: !state.walkMode })),
}));
export default useCameraModeStore;

View File

@ -358,7 +358,8 @@
} }
.controls-player-container { .controls-player-container {
max-width: 50vw; min-width: 26vw;
max-width: 80vw;
border-radius: 15px; border-radius: 15px;
gap: 40px; gap: 40px;
background: var(--background-color); background: var(--background-color);
@ -375,6 +376,12 @@
isolation: isolate; isolation: isolate;
font-weight: 700; font-weight: 700;
padding: 8px; padding: 8px;
transition: all 0.2s;
&.hide {
min-width: none;
width: 92px;
}
.controls-left, .controls-left,
.controls-right { .controls-right {
@ -418,7 +425,7 @@
outline: 1px solid var(--border-color); outline: 1px solid var(--border-color);
color: var(--accent-color); color: var(--accent-color);
} }
&.hide{ &.hide {
width: 32px; width: 32px;
} }
.icon { .icon {

View File

@ -11,7 +11,7 @@ import {
useToggleView, useToggleView,
useToolMode, useToolMode,
} from "../../store/builder/store"; } from "../../store/builder/store";
import { usePlayButtonStore } from "../../store/usePlayButtonStore"; import useCameraModeStore, { usePlayButtonStore } from "../../store/usePlayButtonStore";
import { detectModifierKeys } from "./detectModifierKeys"; import { detectModifierKeys } from "./detectModifierKeys";
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore"; import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
@ -29,6 +29,7 @@ const KeyPressListener: React.FC = () => {
const { setActiveTool } = useActiveTool(); const { setActiveTool } = useActiveTool();
const { clearSelectedZone } = useSelectedZoneStore(); const { clearSelectedZone } = useSelectedZoneStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore(); const { showShortcuts, setShowShortcuts } = useShortcutStore();
const { setWalkMode } = useCameraModeStore();
const isTextInput = (element: Element | null): boolean => const isTextInput = (element: Element | null): boolean =>
element instanceof HTMLInputElement || element instanceof HTMLInputElement ||
@ -168,6 +169,7 @@ const KeyPressListener: React.FC = () => {
} }
if (keyCombination === "ESCAPE") { if (keyCombination === "ESCAPE") {
setWalkMode(false);
setActiveTool("cursor"); setActiveTool("cursor");
setActiveSubTool("cursor"); setActiveSubTool("cursor");
setIsPlaying(false); setIsPlaying(false);