feat: card

This commit is contained in:
TrèsAbhi committed 2024-07-29 13:22:20 -05:00
1 parent ce3c9b936b
commit c12fb0d668
5 files changed
+88 -8

No files matched your search

@@ -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() {
<SceneProps />
{display !== TankopediaDisplay.StaticArmor && <TankModel />}
<ShotDisplay />
<ArmorPlateDisplay />
{/* idk why the shot display doesn't work without suspense here lol */}
<Suspense fallback={<ModelLoader />}>
{display === TankopediaDisplay.DynamicArmor && <Armor />}
@@ -165,8 +169,6 @@ export function TankSandbox() {
)}
<Lighting />
</Suspense>
<ShotDisplay />
</Canvas>
);
}
@@ -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 (
<group position={highlightArmor.point}>
<Html>
<Card
ml="9"
style={{ whiteSpace: 'nowrap', color: highlightArmor.color }}
>
<Flex direction="column">
<Text weight="bold">
{layerTypeNames[highlightArmor.type]}{' '}
{highlightArmor.thickness.toFixed(0)}
<Text size="1" weight="regular">
mm
</Text>
</Text>
{highlightArmor.type !== ArmorType.External && (
<Text size="2" color="gray">
{highlightArmor.thicknessAngled.toFixed(0)}
<Text size="1">
mm {radToDeg(highlightArmor.angle).toFixed(0)}°
</Text>
</Text>
)}
</Flex>
</Card>
</Html>
</group>
);
}
@@ -6,7 +6,7 @@ import { shotStatusColors } from './ShotDisplay';
import { ArmorType } from './SpacedArmorScene';
import { ExternalModuleVariant } from './SpacedArmorSceneComponent';
const layerTypeNames: Record<ArmorType | 'null', string> = {
export const layerTypeNames: Record<ArmorType | 'null', string> = {
[ArmorType.Core]: 'Core',
[ArmorType.Spaced]: 'Spaced',
[ArmorType.External]: 'External',
@@ -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()}`,
};
});
},
});
+13 -1
View File
@@ -11,7 +11,19 @@ interface TankopediaEphemeral {
shot?: Shot;
skills: Record<string, number>;
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 {