From 15cf4ec0f1faadb258c9e33c93797b393f3186b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 30 Jul 2024 13:45:52 -0500 Subject: [PATCH] feat: wireframe --- .../[id]/components/Model/HeroSection.tsx | 54 ++------ .../[id]/components/Thicknesses.tsx | 4 +- .../SpacedArmorSceneComponent/index.tsx | 126 ++++++++++-------- .../components/StaticArmorScene.tsx | 5 +- 4 files changed, 91 insertions(+), 98 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx index 1207bac51..ff3d44f77 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx @@ -4,7 +4,7 @@ import Link from 'next/link'; import { Suspense, use, useEffect, useMemo, useState } from 'react'; import { classIcons } from '../../../../../../components/ClassIcon'; import { ThicknessRange } from '../../../../../../components/StaticArmor/components/StaticArmorScene'; -import { modelDefinitions } from '../../../../../../core/blitzkit/modelDefinitions'; +import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration'; import { tankDefinitions } from '../../../../../../core/blitzkit/tankDefinitions'; import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants'; import { useFullScreen } from '../../../../../../hooks/useFullScreen'; @@ -35,48 +35,22 @@ export function HeroSection({ id }: HeroSectionProps) { ? 'amber' : undefined; const awaitedTankDefinitions = use(tankDefinitions); - const awaitedModelDefinitions = use(modelDefinitions); const tank = awaitedTankDefinitions[id]; const thicknessRange = useMemo(() => { - const thicknesses = Object.values(awaitedTankDefinitions) - .filter((thisTank) => thisTank.tier === tank.tier) - .map((tank) => ({ - model: awaitedModelDefinitions[tank.id], - id: tank.id, - })) - .filter(Boolean) - .map(({ model, id }) => { - const tankThicknesses = Object.values(model.armor.thickness); - const turretThicknesses = Object.values(model.turrets) - .map((turret) => { - const turretThicknesses = Object.values(turret.armor.thickness); - const gunThicknesses = Object.values(turret.guns) - .map((gun) => Object.values(gun.armor.thickness)) - .flat(); + const entries = Object.values(awaitedTankDefinitions); + const filtered = entries.filter((thisTank) => thisTank.tier === tank.tier); + const value = + filtered.reduce((accumulator, thisTank) => { + return ( + accumulator + + resolveNearPenetration( + thisTank.turrets.at(-1)!.guns.at(-1)!.shells[0].penetration, + ) + ); + }, 0) / + ((4 / 3) * filtered.length); - return [...turretThicknesses, ...gunThicknesses]; - }) - .flat(); - const totalThicknesses = [...tankThicknesses, ...turretThicknesses]; - - return totalThicknesses; - }) - .flat(); - - const sortedThicknesses = thicknesses.sort((a, b) => a - b); - const quartileIndex = (1 - 2 ** -6) * (sortedThicknesses.length + 1) - 1; - let quartile: number; - - if (Number.isInteger(quartileIndex)) { - quartile = sortedThicknesses[quartileIndex]; - } else { - quartile = - (sortedThicknesses[Math.floor(quartileIndex)] + - sortedThicknesses[Math.ceil(quartileIndex)]) / - 2; - } - - return { quartile } satisfies ThicknessRange; + return { value } satisfies ThicknessRange; }, [tank.tier]); useEffect(() => { diff --git a/src/app/tools/tankopedia/[id]/components/Thicknesses.tsx b/src/app/tools/tankopedia/[id]/components/Thicknesses.tsx index f890da12e..a80ac6ef3 100644 --- a/src/app/tools/tankopedia/[id]/components/Thicknesses.tsx +++ b/src/app/tools/tankopedia/[id]/components/Thicknesses.tsx @@ -48,7 +48,7 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) { > - {thicknessRange.quartile.toFixed(0)} + {thicknessRange.value.toFixed(0)} {showPrimaryArmor ? : } @@ -85,7 +85,7 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) { > - {thicknessRange.quartile.toFixed(0)} + {thicknessRange.value.toFixed(0)} {showSpacedArmor ? : } diff --git a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx index 365bbae75..62213fe6a 100644 --- a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx +++ b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx @@ -7,7 +7,10 @@ import { DoubleSide, FrontSide, Intersection, + LineBasicMaterial, + Mesh, MeshBasicMaterial, + MeshStandardMaterial, Object3D, Plane, Quaternion, @@ -97,7 +100,7 @@ export function SpacedArmorSceneComponent({ const camera = useThree((state) => state.camera); if (props.static) { - const x = clamp(thickness / props.thicknessRange.quartile, 0, 1); + const x = clamp(thickness / props.thicknessRange.value, 0, 1); let color: Color; let opacity: number; @@ -125,9 +128,9 @@ export function SpacedArmorSceneComponent({ opacity = clamp(opacity, 0, 1); - const material = useMemo( + const surfaceMaterial = useMemo( () => - new MeshBasicMaterial({ + new MeshStandardMaterial({ color, opacity, transparent: true, @@ -136,6 +139,13 @@ export function SpacedArmorSceneComponent({ }), [thickness], ); + const outlineMaterial = useMemo( + () => + new LineBasicMaterial({ + color: color.clone().multiplyScalar(1 - 2 ** -3), + }), + [thickness], + ); /** * hook inside an if statement?? don't panic! I assure you the static prop @@ -147,10 +157,11 @@ export function SpacedArmorSceneComponent({ if (selectedName === undefined) { // nothing selected, go back to defaults - material.opacity = opacity; - material.color = color; - material.depthWrite = props.type !== ArmorType.External; - material.side = FrontSide; + surfaceMaterial.opacity = opacity; + surfaceMaterial.color = color; + surfaceMaterial.depthWrite = props.type !== ArmorType.External; + surfaceMaterial.side = FrontSide; + outlineMaterial.visible = true; } else if ( selectedName === props.name || (props.name.startsWith('chassis_') && @@ -161,19 +172,21 @@ export function SpacedArmorSceneComponent({ !selectedName.includes('_armor_')) ) { // this selected, stand out! - material.opacity = 1; - material.color = color; - material.depthWrite = true; - material.side = DoubleSide; + surfaceMaterial.opacity = 1; + surfaceMaterial.color = color; + surfaceMaterial.depthWrite = true; + surfaceMaterial.side = DoubleSide; + outlineMaterial.visible = true; } else { // something else selected, become background - material.opacity = 1 / 4; - material.color = unselectedColor; - material.depthWrite = props.type !== ArmorType.External; - material.side = FrontSide; + surfaceMaterial.opacity = 1 / 4; + surfaceMaterial.color = unselectedColor; + surfaceMaterial.depthWrite = props.type !== ArmorType.External; + surfaceMaterial.side = FrontSide; + outlineMaterial.visible = false; } - material.transparent = material.opacity < 1; + surfaceMaterial.transparent = surfaceMaterial.opacity < 1; } const unsubscribe = tankopediaEphemeralStore.subscribe( @@ -184,44 +197,53 @@ export function SpacedArmorSceneComponent({ return unsubscribe; }, [thickness]); - return jsxTree(node, { - material, - // renderOrder, - userData: { - type: props.type, - variant: props.type === ArmorType.External ? props.variant : 'gun', - thickness, - } satisfies ArmorUserData, - - onClick(event) { - event.stopPropagation(); - - const bounds = new Box3().setFromObject(event.object); - const point = bounds.min - .clone() - .add(bounds.max) - .divideScalar(2) - .setY(bounds.max.y); - const cameraNormal = camera.position.clone().sub(point).normalize(); - const surfaceNormal = event - .normal!.clone() - .applyQuaternion(event.object.getWorldQuaternion(new Quaternion())); - const angle = surfaceNormal.angleTo(cameraNormal); - const thicknessAngled = thickness / Math.sin(Math.PI / 2 - angle); - - mutateTankopediaEphemeralStore((draft) => { - draft.highlightArmor = { + return ( + <> + {jsxTree(node, { + material: surfaceMaterial, + userData: { type: props.type, - name: props.name, - point, + variant: props.type === ArmorType.External ? props.variant : 'gun', thickness, - thicknessAngled, - angle, - color: `#${color.getHexString()}`, - }; - }); - }, - }); + } satisfies ArmorUserData, + + onClick(event) { + event.stopPropagation(); + + const bounds = new Box3().setFromObject(event.object); + const point = bounds.min + .clone() + .add(bounds.max) + .divideScalar(2) + .setY(bounds.max.y); + const cameraNormal = camera.position.clone().sub(point).normalize(); + const surfaceNormal = event + .normal!.clone() + .applyQuaternion( + event.object.getWorldQuaternion(new Quaternion()), + ); + const angle = surfaceNormal.angleTo(cameraNormal); + const thicknessAngled = thickness / Math.sin(Math.PI / 2 - angle); + + mutateTankopediaEphemeralStore((draft) => { + draft.highlightArmor = { + type: props.type, + name: props.name, + point, + thickness, + thicknessAngled, + angle, + color: `#${color.getHexString()}`, + }; + }); + }, + })} + + + + + + ); } const shoot = useCallback( diff --git a/src/components/StaticArmor/components/StaticArmorScene.tsx b/src/components/StaticArmor/components/StaticArmorScene.tsx index 7db494f5a..f8788b339 100644 --- a/src/components/StaticArmor/components/StaticArmorScene.tsx +++ b/src/components/StaticArmor/components/StaticArmorScene.tsx @@ -18,8 +18,7 @@ interface StaticArmorSceneProps { } export interface ThicknessRange { - // max: number; - quartile: number; + value: number; } export const StaticArmorScene = memo( @@ -57,8 +56,6 @@ export const StaticArmorScene = memo( (state) => state.model.visual.showExternalModules, ); - console.log('yeah'); - useTankTransform(protagonist, turretContainer, gunContainer); return (