From 8daa62ad8eb32a47cbb113240d1da77d2eb6cbd7 Mon Sep 17 00:00:00 2001 From: "azykov@mail.ru" Date: Wed, 3 Jun 2026 21:50:37 +0300 Subject: [PATCH] player controls moved to CharacterView --- src/components/CharacterView.tsx | 53 ++++++++++++++++++++++++++++---- src/components/GameView.tsx | 38 ++--------------------- src/components/SceneView.tsx | 14 ++++----- src/components/SyncRigidBody.tsx | 8 +++-- 4 files changed, 63 insertions(+), 50 deletions(-) diff --git a/src/components/CharacterView.tsx b/src/components/CharacterView.tsx index b4df8ba..c69bed7 100644 --- a/src/components/CharacterView.tsx +++ b/src/components/CharacterView.tsx @@ -2,12 +2,54 @@ import { observer } from "mobx-react-lite"; import type { Character } from "../types"; import { SyncRigidBody } from "./SyncRigidBody"; import { state } from "../state"; +import { useRef } from "react"; +import { Vector3 } from "three"; +import { useFrame } from "@react-three/fiber"; +import { PointerLockControls, useKeyboardControls } from "@react-three/drei"; +import type { RapierRigidBody } from "@react-three/rapier"; -export const CharacterView = observer(function ({ character }: { character: Character }) { +const SPEED = 5; +const _fwd = new Vector3(); + +type CharacterViewProps = { + character: Character; + editMode?: boolean; +} + +export const CharacterView = observer(function ({ character, editMode }: CharacterViewProps) { const pos = character.transform.position; - return ( + const rbRef = useRef(null); + + const [, get] = useKeyboardControls(); + + useFrame(({ camera }) => { + if (state.game?.isPaused || !rbRef.current) + return; + + if (!editMode) { + const { forward, backward, left, right } = get(); + + camera.getWorldDirection(_fwd); + _fwd.y = 0; + _fwd.normalize(); + const fx = _fwd.x, fz = _fwd.z; + + const fwdScale = (forward ? 1 : 0) - (backward ? 1 : 0); + const rightScale = (right ? 1 : 0) - (left ? 1 : 0); + + const vx = (fx * fwdScale - fz * rightScale) * SPEED; + const vz = (fz * fwdScale + fx * rightScale) * SPEED; + + const cur = rbRef.current.linvel(); + rbRef.current.setLinvel({ x: vx, y: cur.y, z: vz }, true); + } + }); + + return (<> + {!editMode && } - + - {/* */} - ); + ); }); diff --git a/src/components/GameView.tsx b/src/components/GameView.tsx index cef45db..3a306c3 100644 --- a/src/components/GameView.tsx +++ b/src/components/GameView.tsx @@ -2,41 +2,9 @@ import { observer } from "mobx-react-lite"; import { SceneView } from "./SceneView"; import { state } from "../state"; import { useFrame, useThree } from "@react-three/fiber"; -import { PointerLockControls, useKeyboardControls } from "@react-three/drei"; -import { Suspense, useRef } from "react"; +import { Suspense } from "react"; import { Physics } from "@react-three/rapier"; -function PlayerMovement() { - const [, get] = useKeyboardControls(); - const dirty = useRef(false); - - useFrame(({ camera }, dt) => { - if (state.game?.isPaused) - return; - - const { forward, backward, left, right } = get(); - const speed = 5 * dt; - if (forward) { camera.translateZ(-speed); dirty.current = true; } - if (backward) { camera.translateZ(speed); dirty.current = true; } - if (left) { camera.translateX(-speed); dirty.current = true; } - if (right) { camera.translateX(speed); dirty.current = true; } - - if (!dirty.current) return; - dirty.current = false; - - const [rx, ry, rz] = camera.rotation.toArray(); - state.game?.setCharacterTransform( - { - position: camera.position.toArray(), - look: [rx, ry, rz], - }, - // do not change velocities - ); - }); - - return { dirty.current = true; }} />; -} - export const GameView = observer(function () { const game = state.game; const { camera } = useThree(); @@ -44,7 +12,8 @@ export const GameView = observer(function () { useFrame((_, delta) => { state.game?.tick(delta); - if (!game) return; + if (!game) + return; const { position, look } = game.camera; camera.position.set(position[0], position[1], position[2]); camera.rotation.set(look[0], look[1], look[2]); @@ -55,7 +24,6 @@ export const GameView = observer(function () { return (<> - diff --git a/src/components/SceneView.tsx b/src/components/SceneView.tsx index cf85138..abcee13 100644 --- a/src/components/SceneView.tsx +++ b/src/components/SceneView.tsx @@ -13,14 +13,14 @@ export const SceneView = observer(function (props: SceneViewProps) { // const rapier = useRapier(); // useFrame((_, dt) => { - // if (props.editMode) - // return; + // if (props.editMode) + // return; - // const game = state.game; - // if (!game || game.isPaused) - // return; + // const game = state.game; + // if (!game || game.isPaused) + // return; - // rapier.step(dt); + // rapier.step(dt); // }) return (<> @@ -34,6 +34,6 @@ export const SceneView = observer(function (props: SceneViewProps) { )) } {/* {props.editMode && } */} - {} + {} ); }); diff --git a/src/components/SyncRigidBody.tsx b/src/components/SyncRigidBody.tsx index 0d5c48f..76187e1 100644 --- a/src/components/SyncRigidBody.tsx +++ b/src/components/SyncRigidBody.tsx @@ -1,6 +1,6 @@ import { RigidBody, type RigidBodyProps, type RapierRigidBody } from "@react-three/rapier"; import { useFrame } from "@react-three/fiber"; -import { useRef } from "react"; +import { useImperativeHandle, useRef, type Ref } from "react"; import { Euler, Quaternion } from "three"; import type { R3, V3 } from "../types"; @@ -15,6 +15,7 @@ export type SyncRigidBodyOnSyncFunction = (data: SyncRigidBodyData) => void; type SyncRigidBodyProps = RigidBodyProps & { onSync: SyncRigidBodyOnSyncFunction; + ref?: Ref; }; const _q = new Quaternion(); @@ -38,8 +39,11 @@ function compareTwoFloatArrays(a: Float64Array, b: Float64Array, epsilon: number return false; } -export function SyncRigidBody({ onSync, children, ...props }: SyncRigidBodyProps) { +export function SyncRigidBody({ onSync, ref, children, ...props }: SyncRigidBodyProps) { const rbRef = useRef(null); + + useImperativeHandle(ref, () => rbRef.current!); + const prevData = useRef(PREV_INIT.slice()); const currentData = useRef(PREV_INIT.slice());