From 6ca9e637dc5be975db53444b49c4fed4468f3475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:37:36 -0600 Subject: [PATCH] feat: loading bar --- .../tankopedia/[id]/components/Control.tsx | 17 +-- .../tankopedia/[id]/components/Loader.tsx | 29 +++++ .../components/{Model.tsx => TankModel.tsx} | 56 ++++++--- src/app/tools/tankopedia/[id]/page.tsx | 113 ++++-------------- src/stitches.config.ts | 2 + 5 files changed, 97 insertions(+), 120 deletions(-) create mode 100644 src/app/tools/tankopedia/[id]/components/Loader.tsx rename src/app/tools/tankopedia/[id]/components/{Model.tsx => TankModel.tsx} (76%) diff --git a/src/app/tools/tankopedia/[id]/components/Control.tsx b/src/app/tools/tankopedia/[id]/components/Control.tsx index f2a395625..30e687573 100644 --- a/src/app/tools/tankopedia/[id]/components/Control.tsx +++ b/src/app/tools/tankopedia/[id]/components/Control.tsx @@ -1,25 +1,18 @@ import { OrbitControls } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; -import { RefObject, useEffect, useRef } from 'react'; -import { Box3, Object3D } from 'three'; +import { useEffect, useRef } from 'react'; import { OrbitControls as OrbitControlsClass } from 'three-stdlib'; import { useTankopedia } from '../../../../../stores/tankopedia'; -interface ControlsProps { - fit: RefObject; -} - -export function Controls({ fit }: ControlsProps) { +export function Controls() { const camera = useThree((state) => state.camera); const orbitControls = useRef(null); const enabled = useTankopedia((state) => state.model.controlsEnabled); useEffect(() => { - const box = new Box3().setFromObject(fit.current!); - - orbitControls.current?.target.set(0, (box.min.y + box.max.y) / 2, 0); - camera.position.set(-5, (box.min.y + box.max.y) / 2, -15); - }, [fit.current]); + camera.position.set(-5, 4, -20); + orbitControls.current?.target.set(0, 1.5, 0); + }, []); return ; } diff --git a/src/app/tools/tankopedia/[id]/components/Loader.tsx b/src/app/tools/tankopedia/[id]/components/Loader.tsx new file mode 100644 index 000000000..aeff48822 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Loader.tsx @@ -0,0 +1,29 @@ +import { Html, useProgress } from '@react-three/drei'; +import { theme } from '../../../../../stitches.config'; + +export function Loader() { + const { progress } = useProgress(); + + return ( + +
+
+
+ + ); +} diff --git a/src/app/tools/tankopedia/[id]/components/Model.tsx b/src/app/tools/tankopedia/[id]/components/TankModel.tsx similarity index 76% rename from src/app/tools/tankopedia/[id]/components/Model.tsx rename to src/app/tools/tankopedia/[id]/components/TankModel.tsx index 264b7b9c3..7a1e47c6e 100644 --- a/src/app/tools/tankopedia/[id]/components/Model.tsx +++ b/src/app/tools/tankopedia/[id]/components/TankModel.tsx @@ -1,9 +1,18 @@ import { useLoader } from '@react-three/fiber'; -import { forwardRef, use, useImperativeHandle, useRef } from 'react'; +import { + forwardRef, + useEffect, + useImperativeHandle, + useRef, + useState, +} from 'react'; import { Group, Vector3 } from 'three'; import { GLTFLoader } from 'three-stdlib'; import { X_AXIS } from '../../../../../constants/axis'; -import { modelDefinitions } from '../../../../../core/blitzkrieg/modelDefinitions'; +import { + ModelDefinitions, + modelDefinitions, +} from '../../../../../core/blitzkrieg/modelDefinitions'; import mutateTankopedia, { useTankopedia, } from '../../../../../stores/tankopedia'; @@ -11,22 +20,33 @@ import { GunContainer } from './GunContainer'; import { HullContainer } from './HullContainer'; import { TurretContainer } from './TurretContainer'; -interface ModelProps { +interface TankModelProps { tankId: number; - gunId: number; turretId: number; + gunId: number; } -export const Model = forwardRef( - ({ gunId, tankId, turretId }, ref) => { - const awaitedModelDefinitions = use(modelDefinitions); - const model = useTankopedia((state) => state.model); +export const TankModel = forwardRef( + ({ tankId, turretId, gunId }, ref) => { + // "TypeError: dispatcher.use is not a function" + // const awaitedModelDefinitions = use(modelDefinitions); + const [awaitedModelDefinitions, setAwaitedModelDefinitions] = useState< + ModelDefinitions | undefined + >(undefined); const gltf = useLoader(GLTFLoader, `/test/${tankId}.glb`); - const gunContainer = useRef(null); + const model = useTankopedia((state) => state.model); const hullContainer = useRef(null); const turretContainer = useRef(null); + const gunContainer = useRef(null); useImperativeHandle(ref, () => hullContainer.current!); + useEffect(() => { + (async () => { + setAwaitedModelDefinitions(await modelDefinitions); + })(); + }, []); + + if (!awaitedModelDefinitions) return null; const tankModelDefinition = awaitedModelDefinitions[tankId]; const turretModelDefinition = tankModelDefinition.turrets[turretId]; @@ -48,24 +68,24 @@ export const Model = forwardRef( yaw={model.hullYaw} ref={hullContainer} onYawStart={() => - mutateTankopedia((state) => { - state.model.controlsEnabled = false; + mutateTankopedia((draft) => { + draft.model.controlsEnabled = false; }) } onYawEnd={(yaw) => { - mutateTankopedia((state) => { - state.model.controlsEnabled = true; - state.model.hullYaw = yaw; + mutateTankopedia((draft) => { + draft.model.controlsEnabled = true; + draft.model.hullYaw = yaw; }); }} onTrackStart={() => { - mutateTankopedia((state) => { - state.model.controlsEnabled = false; + mutateTankopedia((draft) => { + draft.model.controlsEnabled = false; }); }} onTrackEnd={() => { - mutateTankopedia((state) => { - state.model.controlsEnabled = true; + mutateTankopedia((draft) => { + draft.model.controlsEnabled = true; }); }} > diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index 957a9bd86..5a26a0084 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -19,18 +19,16 @@ import { Theme, Tooltip, } from '@radix-ui/themes'; -import { Canvas, useLoader } from '@react-three/fiber'; +import { Canvas } from '@react-three/fiber'; import { go } from 'fuzzysort'; import { debounce } from 'lodash'; import Link from 'next/link'; -import { use, useRef, useState } from 'react'; +import { Suspense, use, useRef, useState } from 'react'; import { Group, Vector3 } from 'three'; -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { Flag } from '../../../../components/Flag'; import { ModuleButtons } from '../../../../components/ModuleButton'; import PageWrapper from '../../../../components/PageWrapper'; import { asset } from '../../../../core/blitzkrieg/asset'; -import { modelDefinitions } from '../../../../core/blitzkrieg/modelDefinitions'; import { TIER_ROMAN_NUMERALS, tankDefinitions, @@ -38,30 +36,24 @@ import { } from '../../../../core/blitzkrieg/tankDefinitions'; import * as styles from '../page.css'; import { Controls } from './components/Control'; -import { GunContainer } from './components/GunContainer'; -import { HullContainer } from './components/HullContainer'; +import { Loader } from './components/Loader'; import { RotationInputs } from './components/RotationInputs'; import { SceneProps } from './components/SceneProps'; -import { TurretContainer } from './components/TurretContainer'; +import { TankModel } from './components/TankModel'; const X_AXIS = new Vector3(1, 0, 0); export default function Page({ params }: { params: { id: string } }) { const id = parseInt(params.id); const awaitedTankDefinitions = use(tankDefinitions); - const awaitedModelDefinitions = use(modelDefinitions); const awaitedTankNamesDiacritics = use(tankNamesDiacritics); const tank = awaitedTankDefinitions[id]; - const tankModelDefinition = awaitedModelDefinitions[id]; const [turret, setTurret] = useState(tank.turrets.at(-1)!); - const turretModelDefinition = tankModelDefinition.turrets[turret.id]; const [gun, setGun] = useState(turret.guns.at(-1)!); - const gunModelDefinition = turretModelDefinition.guns[gun.id]; const [crew, setCrew] = useState(100); const [mode, setMode] = useState('model'); const versusTankSearchInput = useRef(null); const hullContainer = useRef(null); - const turretContainer = useRef(null); const [versusTankSearchResults, setVersusTankSearchResults] = useState< number[] >([]); @@ -70,22 +62,6 @@ export default function Page({ params }: { params: { id: string } }) { const [versusGun, setVersusGun] = useState(versusTurret.guns.at(-1)!); const [versusTankTab, setVersusTankTab] = useState('search'); const canvas = useRef(null); - const gltf = useLoader(GLTFLoader, `/test/${id}.glb`); - const turretOrigin = new Vector3( - tankModelDefinition.turretOrigin[0], - tankModelDefinition.turretOrigin[1], - -tankModelDefinition.turretOrigin[2], - ).applyAxisAngle(X_AXIS, Math.PI / 2); - const gunOrigin = new Vector3( - turretModelDefinition.gunOrigin[0], - turretModelDefinition.gunOrigin[1], - -turretModelDefinition.gunOrigin[2], - ).applyAxisAngle(X_AXIS, Math.PI / 2); - const [turretYaw, setTurretYaw] = useState(0); - const [hullYaw, setHullYaw] = useState(0); - const [gunPitch, setGunPitch] = useState(0); - const [controlsEnabled, setControlsEnabled] = useState(true); - const gunContainer = useRef(null); function handlePointerDown() { window.addEventListener('pointermove', handlePointerMove); @@ -138,63 +114,17 @@ export default function Page({ params }: { params: { id: string } }) { camera={{ fov: 20 }} onPointerDown={handlePointerDown} > - - + - setControlsEnabled(false)} - onYawEnd={(yaw) => { - setControlsEnabled(true); - setHullYaw(yaw); - }} - onTrackStart={() => setControlsEnabled(false)} - onTrackEnd={() => setControlsEnabled(true)} - > - setControlsEnabled(false)} - yawLimits={turretModelDefinition.yaw} - pitchLimits={gunModelDefinition.pitch} - pitch={gunPitch} - onYawEnd={(pitch, yaw) => { - setControlsEnabled(true); - setGunPitch(pitch); - setTurretYaw(yaw); - }} - gunContainer={gunContainer} - turretOrigin={turretOrigin} - yaw={turretYaw} - > - setControlsEnabled(false)} - pitchLimits={gunModelDefinition.pitch} - turretContainer={turretContainer} - yaw={turretYaw} - onPitchEnd={(pitch, yaw) => { - setControlsEnabled(true); - setGunPitch(pitch); - setTurretYaw(yaw); - }} - yawLimits={turretModelDefinition.yaw} - gunOrigin={gunOrigin} - pitch={gunPitch} - model={gunModelDefinition.model} - objects={gltf.scene.children[0].children} - turretOrigin={turretOrigin} - /> - - + }> + + + @@ -218,7 +148,7 @@ export default function Page({ params }: { params: { id: string } }) { {tank.turrets.map((thisTurret) => { return ( - +