update: show repair movement lock indicator

This commit is contained in:
Tom Boullay
2026-05-11 13:15:16 +02:00
parent 00b1780b10
commit e9875206ff
5 changed files with 80 additions and 28 deletions
+2
View File
@@ -2,12 +2,14 @@ import { Crosshair } from "@/components/ui/Crosshair";
import { DebugOverlayLayout } from "@/components/ui/debug/DebugOverlayLayout"; import { DebugOverlayLayout } from "@/components/ui/debug/DebugOverlayLayout";
import { HandTrackingVisualizer } from "@/components/ui/HandTrackingVisualizer"; import { HandTrackingVisualizer } from "@/components/ui/HandTrackingVisualizer";
import { InteractPrompt } from "@/components/ui/InteractPrompt"; import { InteractPrompt } from "@/components/ui/InteractPrompt";
import { RepairMovementLockIndicator } from "@/components/ui/RepairMovementLockIndicator";
export function GameUI(): React.JSX.Element { export function GameUI(): React.JSX.Element {
return ( return (
<> <>
<DebugOverlayLayout /> <DebugOverlayLayout />
<Crosshair /> <Crosshair />
<RepairMovementLockIndicator />
<InteractPrompt /> <InteractPrompt />
<HandTrackingVisualizer /> <HandTrackingVisualizer />
</> </>
@@ -0,0 +1,20 @@
import { useCameraMode } from "@/hooks/debug/useCameraMode";
import { useRepairMovementLocked } from "@/hooks/gameplay/useRepairMovementLocked";
export function RepairMovementLockIndicator(): React.JSX.Element | null {
const cameraMode = useCameraMode();
const movementLocked = useRepairMovementLocked();
if (cameraMode !== "player") return null;
if (!movementLocked) return null;
return (
<div className="repair-movement-lock-indicator" aria-live="polite">
<span
className="repair-movement-lock-indicator__dot"
aria-hidden="true"
/>
<span>Déplacement verrouillé pendant la réparation</span>
</div>
);
}
@@ -0,0 +1,28 @@
import { useGameStore } from "@/managers/stores/useGameStore";
import type { MissionStep } from "@/types/gameplay/repairMission";
export function useRepairMovementLocked(): boolean {
return useGameStore((state) => {
switch (state.mainState) {
case "bike":
return isRepairMovementLocked(state.bike.currentStep);
case "pylone":
return isRepairMovementLocked(state.pylone.currentStep);
case "ferme":
return isRepairMovementLocked(state.ferme.currentStep);
case "intro":
case "outro":
return false;
}
});
}
function isRepairMovementLocked(step: MissionStep): boolean {
return (
step === "inspected" ||
step === "fragmented" ||
step === "scanning" ||
step === "repairing" ||
step === "reassembling"
);
}
+29
View File
@@ -397,6 +397,35 @@ canvas {
letter-spacing: 0.03em; letter-spacing: 0.03em;
} }
.repair-movement-lock-indicator {
position: fixed;
top: 22px;
left: 50%;
z-index: 10;
display: inline-flex;
align-items: center;
gap: 9px;
padding: 9px 13px;
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 999px;
background: rgba(5, 9, 16, 0.72);
color: rgba(255, 255, 255, 0.88);
font-size: 12px;
font-weight: 650;
letter-spacing: 0.02em;
pointer-events: none;
transform: translateX(-50%);
backdrop-filter: blur(10px);
}
.repair-movement-lock-indicator__dot {
width: 7px;
height: 7px;
border-radius: 999px;
background: #38bdf8;
box-shadow: 0 0 14px rgba(56, 189, 248, 0.86);
}
.scene-loading-overlay { .scene-loading-overlay {
position: fixed; position: fixed;
inset: 0; inset: 0;
+1 -28
View File
@@ -23,9 +23,8 @@ import {
PLAYER_WALK_SPEED, PLAYER_WALK_SPEED,
PLAYER_XZ_DAMPING_FACTOR, PLAYER_XZ_DAMPING_FACTOR,
} from "@/data/player/playerConfig"; } from "@/data/player/playerConfig";
import { useRepairMovementLocked } from "@/hooks/gameplay/useRepairMovementLocked";
import { InteractionManager } from "@/managers/InteractionManager"; import { InteractionManager } from "@/managers/InteractionManager";
import { useGameStore } from "@/managers/stores/useGameStore";
import type { MissionStep } from "@/types/gameplay/repairMission";
import type { Vector3Tuple } from "@/types/three/three"; import type { Vector3Tuple } from "@/types/three/three";
type Keys = { type Keys = {
@@ -75,32 +74,6 @@ function setMovementKey(keys: Keys, key: string, pressed: boolean): boolean {
} }
} }
function isRepairMovementLocked(step: MissionStep): boolean {
return (
step === "inspected" ||
step === "fragmented" ||
step === "scanning" ||
step === "repairing" ||
step === "reassembling"
);
}
function useRepairMovementLocked(): boolean {
return useGameStore((state) => {
switch (state.mainState) {
case "bike":
return isRepairMovementLocked(state.bike.currentStep);
case "pylone":
return isRepairMovementLocked(state.pylone.currentStep);
case "ferme":
return isRepairMovementLocked(state.ferme.currentStep);
case "intro":
case "outro":
return false;
}
});
}
export function PlayerController({ export function PlayerController({
octree, octree,
spawnPosition, spawnPosition,