From 7a3bdd8f35fbef1f47ff960b1c22cabfe1eb1f85 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:23:23 -0600 Subject: [PATCH] feat: some more stuff --- .../HeroSection/components/Options/index.tsx | 7 +-- .../TankSandbox/components/Control.tsx | 47 ++++++++++++++++--- .../TankSandbox/components/Lighting.tsx | 3 +- .../TankSandbox/components/TankModel.tsx | 5 +- .../components/TankSandbox/index.tsx | 13 ++--- .../website/src/stores/tankopediaEphemeral.ts | 3 ++ .../src/stores/tankopediaPersistent/index.ts | 5 +- 7 files changed, 58 insertions(+), 25 deletions(-) diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx index a152040e9..2d86be4f5 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx @@ -55,10 +55,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { const hasCustomShell = TankopediaEphemeral.use( (state) => state.customShell !== undefined, ); - const display = TankopediaPersistent.useDeferred( - (state) => state.display, - TankopediaDisplay.Model, - ); + const display = TankopediaEphemeral.use((state) => state.display); const isFullScreen = useFullScreen(); const showGrid = TankopediaPersistent.use((state) => state.showGrid); const showEnvironment = TankopediaPersistent.use( @@ -356,7 +353,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { { - mutateTankopediaPersistent((draft) => { + mutateTankopediaEphemeral((draft) => { draft.display = Number(value); }); }} diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx index 4e831504a..31250ceef 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx @@ -1,7 +1,7 @@ import { OrbitControls } from '@react-three/drei'; import { invalidate, useThree } from '@react-three/fiber'; import { useEffect, useRef, useState } from 'react'; -import { Vector3 } from 'three'; +import { PerspectiveCamera, Vector3 } from 'three'; import { OrbitControls as OrbitControlsClass } from 'three-stdlib'; import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions'; import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits'; @@ -9,6 +9,7 @@ import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment'; import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose'; import { Duel } from '../../../../../../stores/duel'; import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral'; +import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants'; const poseDistances: Record = { [Pose.HullDown]: 15, @@ -18,7 +19,14 @@ const poseDistances: Record = { const modelDefinitions = await awaitableModelDefinitions; +const ARCADE_MODE_DISTANCE = 19; +const ARCADE_MODE_ANGLE = Math.PI / 4; + +export const ARCADE_MODE_FOV = 54; +export const INSPECT_MODE_FOV = 25; + export function Controls() { + const display = TankopediaEphemeral.use((state) => state.display); const duelStore = Duel.useStore(); const tankopediaEphemeralStore = TankopediaEphemeral.useStore(); const camera = useThree((state) => state.camera); @@ -62,8 +70,10 @@ export function Controls() { protagonistTrackModelDefinition.origin.y + antagonistModelDefinition.turret_origin.y + antagonistTurretModelDefinition.gun_origin.y; - const [autoRotate, setAutoRotate] = useState(true); - const initialPosition = [ + const [autoRotate, setAutoRotate] = useState( + display !== TankopediaDisplay.ShootingRange, + ); + let initialPosition = [ -8, protagonistHullOrigin.y + protagonistTurretOrigin.y + @@ -72,9 +82,27 @@ export function Controls() { ] as const; useEffect(() => { - camera.position.set(...initialPosition); - orbitControls.current?.target.set(0, initialPosition[1] / 2, 0); - }, [camera, protagonistTrack, protagonistTank]); + if (display === TankopediaDisplay.ShootingRange) { + (camera as PerspectiveCamera).fov = ARCADE_MODE_FOV; + camera.position.set( + 0, + initialPosition[1] + ARCADE_MODE_DISTANCE * Math.sin(ARCADE_MODE_ANGLE), + ARCADE_MODE_DISTANCE * Math.cos(ARCADE_MODE_ANGLE), + ); + orbitControls.current?.target.set(0, initialPosition[1], 0); + } else { + (camera as PerspectiveCamera).fov = INSPECT_MODE_FOV; + camera.position.set(...initialPosition); + orbitControls.current?.target.set(0, initialPosition[1] / 2, 0); + } + + camera.updateProjectionMatrix(); + }, [ + camera, + protagonistTrack, + protagonistTank, + display === TankopediaDisplay.ShootingRange, + ]); useEffect(() => { const unsubscribeTankopediaEphemeral = tankopediaEphemeralStore.subscribe( @@ -187,13 +215,20 @@ export function Controls() { poseEvent.on(handleDisturbance); canvas.addEventListener('pointerdown', handleDisturbance); + const unsubscribeTankopediaPersistent = tankopediaEphemeralStore.subscribe( + (state) => state.display, + handleDisturbance, + ); return () => { canvas.removeEventListener('pointerdown', handleDisturbance); poseEvent.off(handleDisturbance); + unsubscribeTankopediaPersistent(); }; }, []); + useEffect(() => {}, [display]); + return ( state.protagonist); - const display = TankopediaPersistent.use((state) => state.display); + const display = TankopediaEphemeral.use((state) => state.display); const { hasPbr } = useModel(protagonist.tank.id); const isBrighterLighting = !hasPbr && display !== TankopediaDisplay.StaticArmor; diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx index a8aaf26f7..be6c1cba6 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx @@ -11,7 +11,6 @@ import { useTankModelDefinition } from '../../../../../../hooks/useTankModelDefi import { useTankTransform } from '../../../../../../hooks/useTankTransform'; import { Duel } from '../../../../../../stores/duel'; import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral'; -import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent'; import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants'; import { ModelTankWrapper } from '../../../../../Armor/components/ModelTankWrapper'; @@ -19,7 +18,7 @@ export const TankModel = memo(() => { const mutateDuel = Duel.useMutation(); const duelStore = Duel.useStore(); const protagonist = Duel.use((draft) => draft.protagonist); - const tankopediaPersistentStore = TankopediaPersistent.useStore(); + const tankopediaEphemeralStore = TankopediaEphemeral.useStore(); const track = Duel.use((state) => state.protagonist.track); const turret = Duel.use((state) => state.protagonist.turret); const canvas = useThree((state) => state.gl.domElement); @@ -67,7 +66,7 @@ export const TankModel = memo(() => { function onPointerDown(event: ThreeEvent) { if ( isTrack && - tankopediaPersistentStore.getState().display === + tankopediaEphemeralStore.getState().display === TankopediaDisplay.Model ) { position.set(event.clientX, event.clientY); diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx index 54e3e78a7..0a8b120a3 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx @@ -24,7 +24,7 @@ import { type ThicknessRange, } from '../../../../Armor/components/StaticArmor'; import { AutoClear } from './components/AutoClear'; -import { Controls } from './components/Control'; +import { Controls, INSPECT_MODE_FOV } from './components/Control'; import { Lighting } from './components/Lighting'; import { ModelLoader } from './components/ModelLoader'; import { SceneProps } from './components/SceneProps'; @@ -46,10 +46,8 @@ export const TankSandbox = forwardRef( tankModelDefinition.turrets[protagonist.turret.id]; const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.gun_type!.value.base.id]; - const display = TankopediaPersistent.useDeferred( - (state) => state.display, - TankopediaDisplay.Model, - ); + const display = TankopediaEphemeral.use((state) => state.display); + const tankopediaPersistentStore = TankopediaPersistent.useStore(); const onScreen = useOnScreen(canvas); useImperativeHandle(ref, () => canvas.current!, []); @@ -177,7 +175,10 @@ export const TankSandbox = forwardRef( }); }} style={{ userSelect: 'none' }} - camera={{ fov: 25, far: 32 }} + camera={{ + fov: INSPECT_MODE_FOV, + far: 32, + }} > diff --git a/packages/website/src/stores/tankopediaEphemeral.ts b/packages/website/src/stores/tankopediaEphemeral.ts index 661f3d6b8..30eaf4431 100644 --- a/packages/website/src/stores/tankopediaEphemeral.ts +++ b/packages/website/src/stores/tankopediaEphemeral.ts @@ -11,6 +11,7 @@ import type { ExternalModuleVariant } from '../components/Armor/components/Space import type { XP_MULTIPLIERS } from '../components/Tankopedia/TechTreeSection'; import { awaitableSkillDefinitions } from '../core/awaitables/skillDefinitions'; import { createContextualStore } from '../core/zustand/createContextualStore'; +import { TankopediaDisplay } from './tankopediaPersistent/constants'; export interface ShotLayerBase { index: number; @@ -100,6 +101,7 @@ interface TankopediaEphemeral { ); xpMultiplier: (typeof XP_MULTIPLIERS)[number]; customShell?: ShellDefinition; + display: TankopediaDisplay; } const skillDefinitions = await awaitableSkillDefinitions; @@ -114,6 +116,7 @@ export const TankopediaEphemeral = createContextualStore( model, controlsEnabled: true, xpMultiplier: 1, + display: TankopediaDisplay.Model, })), ); }, diff --git a/packages/website/src/stores/tankopediaPersistent/index.ts b/packages/website/src/stores/tankopediaPersistent/index.ts index 770f95dd7..c70dd4607 100644 --- a/packages/website/src/stores/tankopediaPersistent/index.ts +++ b/packages/website/src/stores/tankopediaPersistent/index.ts @@ -3,7 +3,7 @@ import { create } from 'zustand'; import { persist, subscribeWithSelector } from 'zustand/middleware'; import { ENVIRONMENTS } from '../../constants/lightingEnvironments'; import { createContextualStore } from '../../core/zustand/createContextualStore'; -import { SORT_NAMES, TankopediaDisplay } from './constants'; +import { SORT_NAMES } from './constants'; export type TankopediaSortBy = keyof typeof SORT_NAMES; export type TankopediaSortDirection = 'ascending' | 'descending'; @@ -25,8 +25,6 @@ export interface TankopediaPersistentStore { by: TankopediaSortBy; direction: TankopediaSortDirection; }; - - display: TankopediaDisplay; } export const TankopediaPersistent = createContextualStore(() => @@ -47,7 +45,6 @@ export const TankopediaPersistent = createContextualStore(() => by: 'meta.none', direction: 'ascending', }, - display: TankopediaDisplay.Model, })), { name: 'tankopedia', merge: (a, b) => lodash.merge(b, a) }, ),