diff --git a/packages/website/src/components/Armor/components/StaticArmor.tsx b/packages/website/src/components/Armor/components/StaticArmor.tsx index c6f410263..eedba4cb9 100644 --- a/packages/website/src/components/Armor/components/StaticArmor.tsx +++ b/packages/website/src/components/Armor/components/StaticArmor.tsx @@ -198,7 +198,7 @@ export const StaticArmor = memo(({ thicknessRange }) => { hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); } function handlePointerUp() { mutateDuel((draft) => { @@ -298,7 +298,7 @@ export const StaticArmor = memo(({ thicknessRange }) => { hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); } function handlePointerUp() { mutateTankopediaEphemeral((draft) => { @@ -386,7 +386,7 @@ export const StaticArmor = memo(({ thicknessRange }) => { hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); } function handlePointerUp() { mutateTankopediaEphemeral((draft) => { diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CanvasContent.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CanvasContent.tsx new file mode 100644 index 000000000..74a3b4035 --- /dev/null +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CanvasContent.tsx @@ -0,0 +1,44 @@ +import { invalidate } from '@react-three/fiber'; +import type { QuicklimeEvent } from 'quicklime'; +import { useEffect, useRef } from 'react'; +import type { Group } from 'three'; +import { + modelTransformEvent, + type ModelTransformEventData, +} from '../../../../../../../../core/blitzkit/modelTransform'; +import { ModelChunk } from './ModelChunk'; + +export function CanvasContent() { + const hull = useRef(null); + const gun = useRef(null); + + useEffect(() => { + function handleModelTransformEvent( + event: QuicklimeEvent, + ) { + if (!gun.current) return; + + gun.current.rotation.x = event.data.pitch; + + invalidate(); + } + + modelTransformEvent.on(handleModelTransformEvent); + + return () => { + modelTransformEvent.off(handleModelTransformEvent); + }; + }, []); + + return ( + <> + + + + + + + + + ); +} diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCanvas.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCanvas.tsx index 5cb19ef4e..984919dbf 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCanvas.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCanvas.tsx @@ -1,46 +1,20 @@ import { Canvas } from '@react-three/fiber'; -import { awaitableModelDefinitions } from '../../../../../../../../core/awaitables/modelDefinitions'; -import { useModel } from '../../../../../../../../hooks/useModel'; -import { Duel } from '../../../../../../../../stores/duel'; +import { CanvasContent } from './CanvasContent'; -const modelDefinitions = await awaitableModelDefinitions; +export const zoom = 60; export function FlexibilityCanvas() { - const tank = Duel.use((state) => state.protagonist.tank); - const turret = Duel.use((state) => state.protagonist.turret); - - const tankModel = modelDefinitions.models[tank.id]; - const turretModel = tankModel.turrets[turret.id]; - - const { gltf } = useModel(tank.id); - - const zoom = 60; - const originY = tankModel.turret_origin.z + turretModel.gun_origin.z + 1.5; - const originZ = tankModel.turret_origin.y + turretModel.gun_origin.y; - - console.log(originY, originZ); - return ( - - - - {/* - - - */} - - - - + ); } diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCard.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCard.tsx index dfc13199c..843ba4375 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCard.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCard.tsx @@ -8,6 +8,7 @@ import { applyPitchYawLimits, } from '../../../../../../../../core/blitz/applyPitchYawLimits'; import { hasEquipment } from '../../../../../../../../core/blitzkit/hasEquipment'; +import { modelTransformEvent } from '../../../../../../../../core/blitzkit/modelTransform'; import { Var } from '../../../../../../../../core/radix/var'; import { useLocale } from '../../../../../../../../hooks/useLocale'; import { Duel } from '../../../../../../../../stores/duel'; @@ -155,7 +156,7 @@ export function FlexibilityCard() { const rect = container.current.getBoundingClientRect(); const u = event.clientX - rect.left - rect.width / 2; const v = event.clientY - rect.top - rect.height / 2; - const yaw = Math.atan2(u, -v); + let yaw = Math.atan2(u, -v); const { equipmentMatrix, @@ -189,9 +190,14 @@ export function FlexibilityCard() { hasDownImprovedVerticalStabilizer, ); - setYaw(min[1]); + yaw = min[1]; + const pitch = min[0]; + + setYaw(yaw); setMinPitch(min[0]); setMaxPitch(max[0]); + + modelTransformEvent.dispatch({ pitch, yaw }); }} mb="0" > @@ -229,7 +235,7 @@ export function FlexibilityCard() { > diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/ModelChunk.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/ModelChunk.tsx new file mode 100644 index 000000000..840c9ff41 --- /dev/null +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/ModelChunk.tsx @@ -0,0 +1,72 @@ +import { mauveDark } from '@radix-ui/colors'; +import { LineBasicMaterial, MeshBasicMaterial } from 'three'; +import { awaitableModelDefinitions } from '../../../../../../../../core/awaitables/modelDefinitions'; +import { jsxTree } from '../../../../../../../../core/blitzkit/jsxTree'; +import { useModel } from '../../../../../../../../hooks/useModel'; +import { Duel } from '../../../../../../../../stores/duel'; + +const modelDefinitions = await awaitableModelDefinitions; + +const surfaceMaterial = new MeshBasicMaterial({ + color: mauveDark.mauve6, + toneMapped: false, +}); +const outlineMaterial = new LineBasicMaterial({ + color: mauveDark.mauve8, + toneMapped: false, +}); + +interface Props { + onlyGun?: boolean; +} + +export function ModelChunk({ onlyGun = false }: Props) { + const tank = Duel.use((state) => state.protagonist.tank); + const turret = Duel.use((state) => state.protagonist.turret); + const gun = Duel.use((state) => state.protagonist.gun); + + const tankModel = modelDefinitions.models[tank.id]; + const turretModel = tankModel.turrets[turret.id]; + const gunModel = turretModel.guns[gun.gun_type!.value.base.id]; + + const originZ = tankModel.turret_origin.z + turretModel.gun_origin.z; + const originY = tankModel.turret_origin.y + turretModel.gun_origin.y; + + const { gltf } = useModel(tank.id); + const nodes = Object.values(gltf.nodes); + + return ( + + {nodes.map((node) => { + const isCurrentMantlet = + node.name === + `gun_${gunModel.model_id.toString().padStart(2, '0')}_mask`; + const isCurrentGun = + node.name === `gun_${gunModel.model_id.toString().padStart(2, '0')}`; + const isVisible = isCurrentGun || isCurrentMantlet; + const isHull = node.name === 'hull'; + const isWheel = node.name.startsWith('chassis_wheel_'); + const isTrack = node.name.startsWith('chassis_track_'); + const isCurrentTurret = + node.name === + `turret_${turretModel.model_id.toString().padStart(2, '0')}`; + const isAnythingElse = isHull || isWheel || isTrack || isCurrentTurret; + + if ((onlyGun && isVisible) || (!onlyGun && isAnythingElse)) { + return jsxTree(node, { + mesh(mesh, props, key) { + return ( + <> + + + + + + ); + }, + }); + } + })} + + ); +} diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/index.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/index.tsx index 99787c426..b5fd2a3ee 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/index.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/index.tsx @@ -1,4 +1,4 @@ -import { Box, Flex } from '@radix-ui/themes'; +import { Box, Card, Flex } from '@radix-ui/themes'; import type { MaybeSkeletonComponentProps } from '../../../../../../../types/maybeSkeletonComponentProps'; import { FlexibilityCanvas } from './components/FlexibilityCanvas'; import { FlexibilityCard } from './components/FlexibilityCard'; @@ -7,25 +7,16 @@ export function GunFlexibilityVisualizer({ skeleton, }: MaybeSkeletonComponentProps) { return ( - - - - - - {!skeleton && } - - - + + + + + {!skeleton && } + + + + ); } diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/QuickInputs/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/QuickInputs/index.tsx index 36c75c668..4c19170cb 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/QuickInputs/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/QuickInputs/index.tsx @@ -97,7 +97,7 @@ export function QuickInputs() { hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); mutateDuel((state) => { state.protagonist.pitch = pitch; state.protagonist.yaw = yaw; @@ -140,7 +140,7 @@ export function QuickInputs() { hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); mutateDuel((state) => { state.protagonist.pitch = pitch; state.protagonist.yaw = yaw; diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps/index.tsx index 3bb362c82..95e4de00e 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps/index.tsx @@ -189,7 +189,7 @@ export function SceneProps() { dispersion = Math.max(characteristics.dispersion * penalty, dispersion); } - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); lastPitch = pitch; lastYaw = yaw; 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 696cfd9c1..0e295bdb6 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 @@ -189,7 +189,7 @@ export function TankModel() { hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); } function handlePointerUp() { mutateDuel((draft) => { @@ -296,7 +296,7 @@ export function TankModel() { hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); } function handlePointerUp() { mutateTankopediaEphemeral((draft) => { 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 2d22e0d3c..49a314001 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx @@ -125,7 +125,7 @@ export const TankSandbox = forwardRef( hasDownImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); draft.protagonist.pitch = pitch; draft.protagonist.yaw = yaw; }); @@ -143,7 +143,7 @@ export const TankSandbox = forwardRef( hasImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); draft.protagonist.pitch = pitch; draft.protagonist.yaw = yaw; }); @@ -161,7 +161,7 @@ export const TankSandbox = forwardRef( hasImprovedVerticalStabilizer, ); - modelTransformEvent.emit({ pitch, yaw }); + modelTransformEvent.dispatch({ pitch, yaw }); draft.protagonist.pitch = pitch; draft.protagonist.yaw = yaw; }); diff --git a/packages/website/src/core/blitzkit/modelTransform.ts b/packages/website/src/core/blitzkit/modelTransform.ts index a858b4900..49d7826c7 100644 --- a/packages/website/src/core/blitzkit/modelTransform.ts +++ b/packages/website/src/core/blitzkit/modelTransform.ts @@ -1,8 +1,8 @@ -import { EventManager } from '@blitzkit/core'; +import { Quicklime } from 'quicklime'; export interface ModelTransformEventData { yaw?: number; pitch: number; } -export const modelTransformEvent = new EventManager(); +export const modelTransformEvent = new Quicklime();