fix: format
This commit is contained in:
+5
-5
@@ -15,10 +15,10 @@ function App(): React.JSX.Element {
|
||||
element={
|
||||
<>
|
||||
<Canvas camera={{ position: [85, 60, 85], fov: 42 }} shadows>
|
||||
<Suspense fallback={null}>
|
||||
<World />
|
||||
<DebugPerf />
|
||||
</Suspense>
|
||||
<Suspense fallback={null}>
|
||||
<World />
|
||||
<DebugPerf />
|
||||
</Suspense>
|
||||
</Canvas>
|
||||
<Crosshair />
|
||||
<InteractPrompt />
|
||||
@@ -30,4 +30,4 @@ function App(): React.JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App;
|
||||
|
||||
@@ -107,25 +107,40 @@ export function EditorPage(): React.JSX.Element {
|
||||
setTransformMode(mode);
|
||||
}, []);
|
||||
|
||||
const applySnapshot = useCallback((snapshot: ObjectTransform[]) => {
|
||||
if (!sceneData) return;
|
||||
setSceneData((prev) => {
|
||||
if (!prev) return null;
|
||||
const newMapNodes = prev.mapNodes.map((node, index) => {
|
||||
const transform = snapshot.find((s) => s.uuid === `node-${index}`);
|
||||
if (transform) {
|
||||
return {
|
||||
...node,
|
||||
position: [transform.position.x, transform.position.y, transform.position.z] as [number, number, number],
|
||||
rotation: [transform.rotation.x, transform.rotation.y, transform.rotation.z] as [number, number, number],
|
||||
scale: [transform.scale.x, transform.scale.y, transform.scale.z] as [number, number, number],
|
||||
};
|
||||
}
|
||||
return node;
|
||||
const applySnapshot = useCallback(
|
||||
(snapshot: ObjectTransform[]) => {
|
||||
if (!sceneData) return;
|
||||
setSceneData((prev) => {
|
||||
if (!prev) return null;
|
||||
const newMapNodes = prev.mapNodes.map((node, index) => {
|
||||
const transform = snapshot.find((s) => s.uuid === `node-${index}`);
|
||||
if (transform) {
|
||||
return {
|
||||
...node,
|
||||
position: [
|
||||
transform.position.x,
|
||||
transform.position.y,
|
||||
transform.position.z,
|
||||
] as [number, number, number],
|
||||
rotation: [
|
||||
transform.rotation.x,
|
||||
transform.rotation.y,
|
||||
transform.rotation.z,
|
||||
] as [number, number, number],
|
||||
scale: [
|
||||
transform.scale.x,
|
||||
transform.scale.y,
|
||||
transform.scale.z,
|
||||
] as [number, number, number],
|
||||
};
|
||||
}
|
||||
return node;
|
||||
});
|
||||
return { ...prev, mapNodes: newMapNodes };
|
||||
});
|
||||
return { ...prev, mapNodes: newMapNodes };
|
||||
});
|
||||
}, [sceneData]);
|
||||
},
|
||||
[sceneData],
|
||||
);
|
||||
|
||||
const handleUndo = useCallback(() => {
|
||||
const snapshot = historyManager.current.undo();
|
||||
@@ -148,14 +163,14 @@ export function EditorPage(): React.JSX.Element {
|
||||
const handleSaveToServer = useCallback(async () => {
|
||||
if (!sceneData) return;
|
||||
const json = JSON.stringify(sceneData.mapNodes, null, 2);
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/save-map", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: json,
|
||||
});
|
||||
|
||||
|
||||
if (response.ok) {
|
||||
alert("Map enregistrée avec succès!");
|
||||
} else {
|
||||
@@ -192,8 +207,16 @@ export function EditorPage(): React.JSX.Element {
|
||||
if (!sceneData) return;
|
||||
const snapshot = sceneData.mapNodes.map((node, index) => ({
|
||||
uuid: `node-${index}`,
|
||||
position: { x: node.position[0], y: node.position[1], z: node.position[2] },
|
||||
rotation: { x: node.rotation[0], y: node.rotation[1], z: node.rotation[2] },
|
||||
position: {
|
||||
x: node.position[0],
|
||||
y: node.position[1],
|
||||
z: node.position[2],
|
||||
},
|
||||
rotation: {
|
||||
x: node.rotation[0],
|
||||
y: node.rotation[1],
|
||||
z: node.rotation[2],
|
||||
},
|
||||
scale: { x: node.scale[0], y: node.scale[1], z: node.scale[2] },
|
||||
}));
|
||||
historyManager.current.saveSnapshot(snapshot);
|
||||
@@ -203,8 +226,16 @@ export function EditorPage(): React.JSX.Element {
|
||||
if (!sceneData) return;
|
||||
const snapshot = sceneData.mapNodes.map((node, index) => ({
|
||||
uuid: `node-${index}`,
|
||||
position: { x: node.position[0], y: node.position[1], z: node.position[2] },
|
||||
rotation: { x: node.rotation[0], y: node.rotation[1], z: node.rotation[2] },
|
||||
position: {
|
||||
x: node.position[0],
|
||||
y: node.position[1],
|
||||
z: node.position[2],
|
||||
},
|
||||
rotation: {
|
||||
x: node.rotation[0],
|
||||
y: node.rotation[1],
|
||||
z: node.rotation[2],
|
||||
},
|
||||
scale: { x: node.scale[0], y: node.scale[1], z: node.scale[2] },
|
||||
}));
|
||||
historyManager.current.saveSnapshot(snapshot);
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { useRef, useEffect, useCallback, forwardRef, useImperativeHandle } from 'react';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { OrbitControls } from '@react-three/drei';
|
||||
import * as THREE from 'three';
|
||||
import {
|
||||
useRef,
|
||||
useEffect,
|
||||
useCallback,
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
} from "react";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { OrbitControls } from "@react-three/drei";
|
||||
import * as THREE from "three";
|
||||
|
||||
interface FlyControllerProps {
|
||||
speed?: number;
|
||||
@@ -14,89 +20,101 @@ export interface FlyControllerRef {
|
||||
controls: any;
|
||||
}
|
||||
|
||||
const FlyControllerInner = forwardRef<FlyControllerRef, FlyControllerProps>(({
|
||||
speed = 10,
|
||||
verticalSpeed = 5,
|
||||
onPositionChange,
|
||||
disabled = false
|
||||
}, ref) => {
|
||||
const { camera } = useThree();
|
||||
const keys = useRef<{ [key: string]: boolean }>({});
|
||||
const controlsRef = useRef<any>(null);
|
||||
const lastPosition = useRef(new THREE.Vector3());
|
||||
const FlyControllerInner = forwardRef<FlyControllerRef, FlyControllerProps>(
|
||||
(
|
||||
{ speed = 10, verticalSpeed = 5, onPositionChange, disabled = false },
|
||||
ref,
|
||||
) => {
|
||||
const { camera } = useThree();
|
||||
const keys = useRef<{ [key: string]: boolean }>({});
|
||||
const controlsRef = useRef<any>(null);
|
||||
const lastPosition = useRef(new THREE.Vector3());
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
controls: controlsRef.current,
|
||||
}));
|
||||
useImperativeHandle(ref, () => ({
|
||||
controls: controlsRef.current,
|
||||
}));
|
||||
|
||||
const handleKeyDown = useCallback((e: KeyboardEvent) => {
|
||||
keys.current[e.code] = true;
|
||||
}, []);
|
||||
const handleKeyDown = useCallback((e: KeyboardEvent) => {
|
||||
keys.current[e.code] = true;
|
||||
}, []);
|
||||
|
||||
const handleKeyUp = useCallback((e: KeyboardEvent) => {
|
||||
keys.current[e.code] = false;
|
||||
}, []);
|
||||
const handleKeyUp = useCallback((e: KeyboardEvent) => {
|
||||
keys.current[e.code] = false;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
window.addEventListener('keyup', handleKeyUp);
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
window.removeEventListener('keyup', handleKeyUp);
|
||||
};
|
||||
}, [handleKeyDown, handleKeyUp]);
|
||||
useEffect(() => {
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
window.addEventListener("keyup", handleKeyUp);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyDown);
|
||||
window.removeEventListener("keyup", handleKeyUp);
|
||||
};
|
||||
}, [handleKeyDown, handleKeyUp]);
|
||||
|
||||
useFrame((_, delta) => {
|
||||
// En mode disabled: ZQSD désactivé, on garde que OrbitControls
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
useFrame((_, delta) => {
|
||||
// En mode disabled: ZQSD désactivé, on garde que OrbitControls
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ZQSD (AZERTY): Z=forward, S=backward, Q=left, D=right
|
||||
// Support aussi QWERTY et flèches
|
||||
const isForward = keys.current['KeyW'] || keys.current['KeyZ'] || keys.current['ArrowUp'];
|
||||
const isBackward = keys.current['KeyS'] || keys.current['ArrowDown'];
|
||||
const isLeft = keys.current['KeyQ'] || keys.current['KeyA'] || keys.current['ArrowLeft'];
|
||||
const isRight = keys.current['KeyD'] || keys.current['ArrowRight'];
|
||||
// ZQSD (AZERTY): Z=forward, S=backward, Q=left, D=right
|
||||
// Support aussi QWERTY et flèches
|
||||
const isForward =
|
||||
keys.current["KeyW"] || keys.current["KeyZ"] || keys.current["ArrowUp"];
|
||||
const isBackward = keys.current["KeyS"] || keys.current["ArrowDown"];
|
||||
const isLeft =
|
||||
keys.current["KeyQ"] ||
|
||||
keys.current["KeyA"] ||
|
||||
keys.current["ArrowLeft"];
|
||||
const isRight = keys.current["KeyD"] || keys.current["ArrowRight"];
|
||||
|
||||
const direction = new THREE.Vector3();
|
||||
const frontVector = new THREE.Vector3(0, 0, Number(isBackward) - Number(isForward));
|
||||
const sideVector = new THREE.Vector3(Number(isRight) - Number(isLeft), 0, 0);
|
||||
const direction = new THREE.Vector3();
|
||||
const frontVector = new THREE.Vector3(
|
||||
0,
|
||||
0,
|
||||
Number(isBackward) - Number(isForward),
|
||||
);
|
||||
const sideVector = new THREE.Vector3(
|
||||
Number(isRight) - Number(isLeft),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
direction.subVectors(frontVector, sideVector);
|
||||
if (direction.lengthSq() > 0) {
|
||||
direction.normalize().multiplyScalar(speed * delta);
|
||||
direction.applyQuaternion(camera.quaternion);
|
||||
camera.position.add(direction);
|
||||
}
|
||||
direction.subVectors(frontVector, sideVector);
|
||||
if (direction.lengthSq() > 0) {
|
||||
direction.normalize().multiplyScalar(speed * delta);
|
||||
direction.applyQuaternion(camera.quaternion);
|
||||
camera.position.add(direction);
|
||||
}
|
||||
|
||||
// Space = monter, Shift = descendre
|
||||
if (keys.current['Space']) {
|
||||
camera.position.y += verticalSpeed * delta;
|
||||
}
|
||||
if (keys.current['ShiftLeft'] || keys.current['ShiftRight']) {
|
||||
camera.position.y -= verticalSpeed * delta;
|
||||
}
|
||||
// Space = monter, Shift = descendre
|
||||
if (keys.current["Space"]) {
|
||||
camera.position.y += verticalSpeed * delta;
|
||||
}
|
||||
if (keys.current["ShiftLeft"] || keys.current["ShiftRight"]) {
|
||||
camera.position.y -= verticalSpeed * delta;
|
||||
}
|
||||
|
||||
if (onPositionChange && !camera.position.equals(lastPosition.current)) {
|
||||
lastPosition.current.copy(camera.position);
|
||||
onPositionChange(camera.position);
|
||||
}
|
||||
});
|
||||
if (onPositionChange && !camera.position.equals(lastPosition.current)) {
|
||||
lastPosition.current.copy(camera.position);
|
||||
onPositionChange(camera.position);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<OrbitControls
|
||||
ref={controlsRef}
|
||||
makeDefault
|
||||
enableDamping
|
||||
dampingFactor={0.05}
|
||||
mouseButtons={{
|
||||
LEFT: THREE.MOUSE.ROTATE,
|
||||
MIDDLE: THREE.MOUSE.DOLLY,
|
||||
RIGHT: THREE.MOUSE.PAN,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<OrbitControls
|
||||
ref={controlsRef}
|
||||
makeDefault
|
||||
enableDamping
|
||||
dampingFactor={0.05}
|
||||
mouseButtons={{
|
||||
LEFT: THREE.MOUSE.ROTATE,
|
||||
MIDDLE: THREE.MOUSE.DOLLY,
|
||||
RIGHT: THREE.MOUSE.PAN,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default FlyControllerInner;
|
||||
export default FlyControllerInner;
|
||||
|
||||
@@ -92,9 +92,9 @@ export default function MapViewer({
|
||||
<axesHelper args={[10]} />
|
||||
|
||||
<group
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!(window as any).isTransforming) {
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!(window as any).isTransforming) {
|
||||
onSelectNode(null);
|
||||
}
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user