From c12fb0d668ce1c8c186df33e0aa4ad84f9dd6158 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Mon, 29 Jul 2024 13:22:20 -0500
Subject: [PATCH] feat: card
---
.../[id]/components/Model/TankSandbox.tsx | 6 ++-
.../Armor/components/ArmorPlateDisplay.tsx | 43 +++++++++++++++++++
.../Armor/components/ShotDisplayCard.tsx | 2 +-
.../SpacedArmorSceneComponent/index.tsx | 31 +++++++++++--
src/stores/tankopediaEphemeral.ts | 14 +++++-
5 files changed, 88 insertions(+), 8 deletions(-)
create mode 100644 src/components/Armor/components/ArmorPlateDisplay.tsx
diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx
index 3dda8bec2..ffd7a967b 100644
--- a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx
@@ -1,6 +1,7 @@
import { Canvas } from '@react-three/fiber';
import { Suspense, use, useEffect, useRef } from 'react';
import { Armor } from '../../../../../../components/Armor';
+import { ArmorPlateDisplay } from '../../../../../../components/Armor/components/ArmorPlateDisplay';
import { ShotDisplay } from '../../../../../../components/Armor/components/ShotDisplay';
import { StaticArmor } from '../../../../../../components/StaticArmor';
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
@@ -157,6 +158,9 @@ export function TankSandbox() {
{display !== TankopediaDisplay.StaticArmor && }
+
+
+
{/* idk why the shot display doesn't work without suspense here lol */}
}>
{display === TankopediaDisplay.DynamicArmor && }
@@ -165,8 +169,6 @@ export function TankSandbox() {
)}
-
-
);
}
diff --git a/src/components/Armor/components/ArmorPlateDisplay.tsx b/src/components/Armor/components/ArmorPlateDisplay.tsx
new file mode 100644
index 000000000..07370c593
--- /dev/null
+++ b/src/components/Armor/components/ArmorPlateDisplay.tsx
@@ -0,0 +1,43 @@
+import { Card, Flex, Text } from '@radix-ui/themes';
+import { Html } from '@react-three/drei';
+import { radToDeg } from 'three/src/math/MathUtils';
+import * as TankopediaEphemeral from '../../../stores/tankopediaEphemeral';
+import { layerTypeNames } from './ShotDisplayCard';
+import { ArmorType } from './SpacedArmorScene';
+
+export function ArmorPlateDisplay() {
+ const highlightArmor = TankopediaEphemeral.use(
+ (state) => state.highlightArmor,
+ );
+
+ if (highlightArmor === undefined) return null;
+
+ return (
+
+
+
+
+
+ {layerTypeNames[highlightArmor.type]}{' '}
+ {highlightArmor.thickness.toFixed(0)}
+
+ mm
+
+
+ {highlightArmor.type !== ArmorType.External && (
+
+ {highlightArmor.thicknessAngled.toFixed(0)}
+
+ mm {radToDeg(highlightArmor.angle).toFixed(0)}°
+
+
+ )}
+
+
+
+
+ );
+}
diff --git a/src/components/Armor/components/ShotDisplayCard.tsx b/src/components/Armor/components/ShotDisplayCard.tsx
index b7b29cbaf..313eee2f3 100644
--- a/src/components/Armor/components/ShotDisplayCard.tsx
+++ b/src/components/Armor/components/ShotDisplayCard.tsx
@@ -6,7 +6,7 @@ import { shotStatusColors } from './ShotDisplay';
import { ArmorType } from './SpacedArmorScene';
import { ExternalModuleVariant } from './SpacedArmorSceneComponent';
-const layerTypeNames: Record = {
+export const layerTypeNames: Record = {
[ArmorType.Core]: 'Core',
[ArmorType.Spaced]: 'Spaced',
[ArmorType.External]: 'External',
diff --git a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx
index 5456ac513..14c433d95 100644
--- a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx
+++ b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx
@@ -3,6 +3,8 @@ import { clamp } from 'lodash';
import { useCallback, useEffect, useMemo } from 'react';
import {
Color,
+ DoubleSide,
+ FrontSide,
Intersection,
MeshBasicMaterial,
MeshStandardMaterial,
@@ -74,6 +76,7 @@ const omitMaterial = new MeshBasicMaterial({
depthWrite: true,
});
const unselectedColor = new Color(0x404040);
+const externalModuleColor = new Color(0, 1 / 4, 1 / 2);
/**
* Render orders allocations:
@@ -395,7 +398,7 @@ export function SpacedArmorSceneComponent({
break;
case ArmorType.External:
- color = new Color(0, 1, 1);
+ color = externalModuleColor;
opacity = 1 / 8;
renderOrder = 0;
depthWrite = false;
@@ -427,9 +430,10 @@ export function SpacedArmorSceneComponent({
if (selectedName === undefined) {
// nothing selected, go back to defaults
material.opacity = opacity;
- material.transparent = true;
+ material.transparent = opacity < 1;
material.color = color;
material.depthWrite = props.type !== ArmorType.External;
+ material.side = FrontSide;
} else if (
selectedName === props.name ||
(props.name.startsWith('chassis_') &&
@@ -444,17 +448,19 @@ export function SpacedArmorSceneComponent({
material.transparent = false;
material.color = color;
material.depthWrite = true;
+ material.side = DoubleSide;
} else {
// something else selected, become background
material.opacity = 1 / 4;
material.transparent = true;
material.color = unselectedColor;
material.depthWrite = props.type !== ArmorType.External;
+ material.side = FrontSide;
}
}
const unsubscribe = tankopediaEphemeralStore.subscribe(
- (state) => state.highlightArmor,
+ (state) => state.highlightArmor?.name,
handleHighlightArmor,
);
@@ -474,8 +480,25 @@ export function SpacedArmorSceneComponent({
onClick(event) {
event.stopPropagation();
+
+ const { point } = event;
+ 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 = props.name;
+ draft.highlightArmor = {
+ type: props.type,
+ name: props.name,
+ point,
+ thickness,
+ thicknessAngled,
+ angle,
+ color: `#${color.getHexString()}`,
+ };
});
},
});
diff --git a/src/stores/tankopediaEphemeral.ts b/src/stores/tankopediaEphemeral.ts
index 0e94e02c5..5960620ab 100644
--- a/src/stores/tankopediaEphemeral.ts
+++ b/src/stores/tankopediaEphemeral.ts
@@ -11,7 +11,19 @@ interface TankopediaEphemeral {
shot?: Shot;
skills: Record;
controlsEnabled: boolean;
- highlightArmor?: string;
+ highlightArmor?: {
+ name: string;
+ point: Vector3;
+ thickness: number;
+ color: string;
+ } & (
+ | {
+ type: ArmorType.Core | ArmorType.Spaced;
+ thicknessAngled: number;
+ angle: number;
+ }
+ | { type: ArmorType.External }
+ );
}
export interface ShotLayerBase {