From 1eed905e8bc384e20865d5a7a1f1a0dd0a1c55a8 Mon Sep 17 00:00:00 2001 From: Tom Boullay Date: Thu, 16 Apr 2026 11:00:08 +0200 Subject: [PATCH] fix: archi player --- src/world/World.tsx | 4 +- src/world/player/PlayerCamera.tsx | 25 ++++++++++ src/world/player/PlayerComponent.tsx | 11 +++++ ...FPSController.tsx => PlayerController.tsx} | 48 ++++++++++--------- 4 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 src/world/player/PlayerCamera.tsx create mode 100644 src/world/player/PlayerComponent.tsx rename src/world/player/{FPSController.tsx => PlayerController.tsx} (77%) diff --git a/src/world/World.tsx b/src/world/World.tsx index 8213516..3354220 100644 --- a/src/world/World.tsx +++ b/src/world/World.tsx @@ -5,7 +5,7 @@ import { DebugHelpers } from "@/utils/debug/scene/DebugHelpers"; import { Environment } from "@/world/Environment"; import { Lighting } from "@/world/Lighting"; import { Map } from "@/world/Map"; -import { FPSController } from "@/world/player/FPSController"; +import { PlayerComponent } from "@/world/player/PlayerComponent"; export function World(): React.JSX.Element { const cameraMode = useCameraMode(); @@ -15,7 +15,7 @@ export function World(): React.JSX.Element { - {cameraMode === "debug" ? : } + {cameraMode === "debug" ? : } diff --git a/src/world/player/PlayerCamera.tsx b/src/world/player/PlayerCamera.tsx new file mode 100644 index 0000000..ae7ce5d --- /dev/null +++ b/src/world/player/PlayerCamera.tsx @@ -0,0 +1,25 @@ +import { useEffect } from "react"; +import { PointerLockControls } from "@react-three/drei"; +import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; + +export const PLAYER_EYE_HEIGHT = 1.75; + +const PLAYER_SPAWN_POSITION = new THREE.Vector3(0, PLAYER_EYE_HEIGHT, 6); +const PLAYER_LOOK_AT = new THREE.Vector3(0, PLAYER_EYE_HEIGHT, 0); + +export function PlayerCamera(): React.JSX.Element { + const camera = useThree((state) => state.camera); + + useEffect(() => { + camera.position.copy(PLAYER_SPAWN_POSITION); + camera.lookAt(PLAYER_LOOK_AT); + camera.updateProjectionMatrix(); + + return () => { + document.exitPointerLock?.(); + }; + }, [camera]); + + return ; +} diff --git a/src/world/player/PlayerComponent.tsx b/src/world/player/PlayerComponent.tsx new file mode 100644 index 0000000..8cd1f19 --- /dev/null +++ b/src/world/player/PlayerComponent.tsx @@ -0,0 +1,11 @@ +import { PlayerCamera } from "@/world/player/PlayerCamera"; +import { PlayerController } from "@/world/player/PlayerController"; + +export function PlayerComponent(): React.JSX.Element { + return ( + <> + + + + ); +} diff --git a/src/world/player/FPSController.tsx b/src/world/player/PlayerController.tsx similarity index 77% rename from src/world/player/FPSController.tsx rename to src/world/player/PlayerController.tsx index 40bf4d7..92a8206 100644 --- a/src/world/player/FPSController.tsx +++ b/src/world/player/PlayerController.tsx @@ -1,11 +1,11 @@ import { useEffect, useRef } from "react"; -import { PointerLockControls } from "@react-three/drei"; import { useFrame, useThree } from "@react-three/fiber"; import * as THREE from "three"; +import { PLAYER_EYE_HEIGHT } from "@/world/player/PlayerCamera"; -const PLAYER_EYE_HEIGHT = 1.75; -const PLAYER_SPAWN_POSITION = new THREE.Vector3(0, PLAYER_EYE_HEIGHT, 6); -const PLAYER_LOOK_AT = new THREE.Vector3(0, PLAYER_EYE_HEIGHT, 0); +const JUMP_HEIGHT = 1; +const GRAVITY = 18; +const JUMP_VELOCITY = Math.sqrt(2 * GRAVITY * JUMP_HEIGHT); const MOVE_SPEED = 5; type PlayerKeys = { @@ -22,47 +22,43 @@ const DEFAULT_KEYS: PlayerKeys = { right: false, }; -export function FPSController(): React.JSX.Element { +export function PlayerController(): null { const camera = useThree((state) => state.camera); const keys = useRef({ ...DEFAULT_KEYS }); const interact = useRef<() => void>(() => {}); + const verticalVelocity = useRef(0); const forward = useRef(new THREE.Vector3()); const right = useRef(new THREE.Vector3()); const movement = useRef(new THREE.Vector3()); const up = useRef(new THREE.Vector3(0, 1, 0)); - useEffect(() => { - camera.position.copy(PLAYER_SPAWN_POSITION); - camera.lookAt(PLAYER_LOOK_AT); - camera.updateProjectionMatrix(); - - return () => { - document.exitPointerLock?.(); - }; - }, [camera]); - useEffect(() => { const handleKeyChange = (pressed: boolean) => (event: KeyboardEvent): void => { - switch (event.code) { - case "KeyZ": + switch (event.key.toLowerCase()) { + case "z": keys.current.forward = pressed; break; - case "KeyS": + case "s": keys.current.backward = pressed; break; - case "KeyQ": + case "q": keys.current.left = pressed; break; - case "KeyD": + case "d": keys.current.right = pressed; break; - case "KeyE": + case "e": if (pressed) { interact.current(); } break; + case " ": + if (pressed && camera.position.y <= PLAYER_EYE_HEIGHT) { + verticalVelocity.current = JUMP_VELOCITY; + } + break; default: return; } @@ -81,7 +77,7 @@ export function FPSController(): React.JSX.Element { window.removeEventListener("keyup", handleKeyUp); keys.current = { ...DEFAULT_KEYS }; }; - }, []); + }, [camera]); useFrame((_, delta) => { const currentForward = forward.current; @@ -119,7 +115,13 @@ export function FPSController(): React.JSX.Element { camera.position.add(currentMovement); } + verticalVelocity.current -= GRAVITY * delta; + + const nextY = camera.position.y + verticalVelocity.current * delta; + camera.position.set(camera.position.x, nextY, camera.position.z); + if (camera.position.y < PLAYER_EYE_HEIGHT) { + verticalVelocity.current = 0; camera.position.set( camera.position.x, PLAYER_EYE_HEIGHT, @@ -128,5 +130,5 @@ export function FPSController(): React.JSX.Element { } }); - return ; + return null; }