mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: new tab
This commit is contained in:
1 parent
7f056500ca
commit
7605e1d6f2
10 files changed
+136
-55
No files matched your search
@@ -855,6 +855,10 @@
|
||||
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
||||
|
||||
"sandbox": {
|
||||
"dissector": {
|
||||
"name": "Dissector"
|
||||
},
|
||||
|
||||
"poses": {
|
||||
"hull_down": "Hull down",
|
||||
"face_hug": "Face hug",
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { memo } from 'react';
|
||||
import { DissectorSceneComponent } from './DissectorSceneComponent';
|
||||
|
||||
export const Dissector = memo(() => {
|
||||
return (
|
||||
<group>
|
||||
<DissectorSceneComponent group="hull" />
|
||||
<DissectorSceneComponent group="chassis" />
|
||||
<group position={[0.7, 1.6, 0]}>
|
||||
<DissectorSceneComponent group="turret_01" />
|
||||
<group position={[1, 0.36, 0]}>
|
||||
<DissectorSceneComponent group="gun_01" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
import { asset } from '@blitzkit/core';
|
||||
import { useGLTF } from '@react-three/drei';
|
||||
import {
|
||||
Color,
|
||||
DoubleSide,
|
||||
LineBasicMaterial,
|
||||
Material,
|
||||
MeshStandardMaterial,
|
||||
} from 'three';
|
||||
import { jsxTree } from '../../../core/blitzkit/jsxTree';
|
||||
import { Duel } from '../../../stores/duel';
|
||||
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
|
||||
import { groupNameRegex } from './StaticArmorSceneComponent';
|
||||
|
||||
interface DissectorSceneComponentProps {
|
||||
group: string;
|
||||
}
|
||||
|
||||
const armorColor = new Color().multiplyScalar(1 / 16);
|
||||
|
||||
const moduleColor: Record<string, Color> = {
|
||||
Armor: armorColor,
|
||||
ArmorScreen: armorColor,
|
||||
|
||||
Commander: new Color('white'),
|
||||
Driver: new Color('white'),
|
||||
Gunner1: new Color('white'),
|
||||
Loader1: new Color('white'),
|
||||
|
||||
SurveyingDevice: new Color('purple'),
|
||||
Radio: new Color('indigo'),
|
||||
Gun: new Color('pink'),
|
||||
FuelTank: new Color('yellow'),
|
||||
Engine: new Color('orange'),
|
||||
AmmoBay: new Color('gold'),
|
||||
LeftTrack: new Color('green'),
|
||||
RightTrack: new Color('green'),
|
||||
TurretRotator: new Color('blue'),
|
||||
Transmission: new Color('cyan'),
|
||||
};
|
||||
const moduleOutlineColor: Record<string, Color> = {};
|
||||
|
||||
for (const key in moduleColor) {
|
||||
moduleOutlineColor[key] = moduleColor[key].clone().multiplyScalar(4);
|
||||
}
|
||||
|
||||
export function DissectorSceneComponent({
|
||||
group,
|
||||
}: DissectorSceneComponentProps) {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
const gltf = useGLTF(asset(`tanks/${tank.id}/collision/${group}.glb`));
|
||||
const armor = TankopediaEphemeral.use((state) => state.armor);
|
||||
const groupName = group.match(groupNameRegex)![1];
|
||||
const groupArmor = armor.groups[groupName];
|
||||
|
||||
return jsxTree(gltf.scene, {
|
||||
mesh(mesh, props) {
|
||||
if (!(mesh.material instanceof Material)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const armorName = mesh.material.name;
|
||||
const armorPlate = groupArmor.armors[armorName];
|
||||
|
||||
if (!(armorPlate.type in moduleColor)) {
|
||||
throw new TypeError(`Unhandled armor type: ${armorPlate.type}`);
|
||||
}
|
||||
|
||||
const material = new MeshStandardMaterial({
|
||||
side: DoubleSide,
|
||||
color: moduleColor[armorPlate.type],
|
||||
});
|
||||
const outlineMaterial = new LineBasicMaterial({
|
||||
side: DoubleSide,
|
||||
color: moduleOutlineColor[armorPlate.type],
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<mesh {...props} material={material} />
|
||||
|
||||
<lineSegments material={outlineMaterial}>
|
||||
<edgesGeometry args={[props.geometry, 45]} />
|
||||
</lineSegments>
|
||||
</>
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,62 +1,19 @@
|
||||
import { memo } from 'react';
|
||||
import { StaticArmorSceneComponents } from './StaticArmorSceneComponents';
|
||||
import { StaticArmorSceneComponent } from './StaticArmorSceneComponent';
|
||||
|
||||
export interface ThicknessRange {
|
||||
value: number;
|
||||
}
|
||||
|
||||
export const StaticArmor = memo(() => {
|
||||
// const wrapper = useRef<Group>(null);
|
||||
// const turretContainer = useRef<Group>(null);
|
||||
// const gunContainer = useRef<Group>(null);
|
||||
// const protagonist = Duel.use((draft) => draft.protagonist);
|
||||
// const tank = Duel.use((state) => state.protagonist.tank);
|
||||
// const track = Duel.use((state) => state.protagonist.track);
|
||||
// const turret = Duel.use((state) => state.protagonist.turret);
|
||||
// const gun = Duel.use((state) => state.protagonist.gun);
|
||||
// const { gltf: armorGltf } = useArmor(tank.id);
|
||||
// const { gltf: modelGltf } = useModel(tank.id);
|
||||
// const armorNodes = Object.values(armorGltf.nodes);
|
||||
// const modelNodes = Object.values(modelGltf.nodes);
|
||||
// const tankModelDefinition = useTankModelDefinition();
|
||||
// const trackModelDefinition = tankModelDefinition.tracks[track.id];
|
||||
// const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
||||
// const gunModelDefinition =
|
||||
// turretModelDefinition.guns[gun.gun_type!.value.base.id];
|
||||
// const hullOrigin = correctZYTuple(trackModelDefinition.origin);
|
||||
// const turretOrigin = correctZYTuple(tankModelDefinition.turret_origin);
|
||||
// const gunOrigin = correctZYTuple(turretModelDefinition.gun_origin);
|
||||
// const mutateDuel = Duel.useMutation();
|
||||
// const canvas = useThree((state) => state.gl.domElement);
|
||||
// const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||
// const duelStore = Duel.useStore();
|
||||
// const maskOrigin =
|
||||
// gunModelDefinition.mask === undefined
|
||||
// ? undefined
|
||||
// : gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y;
|
||||
// const showPrimaryArmor = TankopediaPersistent.use(
|
||||
// (state) => state.showPrimaryArmor,
|
||||
// );
|
||||
// const showSpacedArmor = TankopediaPersistent.use(
|
||||
// (state) => state.showSpacedArmor,
|
||||
// );
|
||||
// const showExternalModules = TankopediaPersistent.use(
|
||||
// (state) => state.showExternalModules,
|
||||
// );
|
||||
// const isDynamicArmorActive = Duel.use((state) =>
|
||||
// state.protagonist.consumables.includes(73),
|
||||
// );
|
||||
|
||||
// useTankTransform(track, turret, turretContainer, gunContainer);
|
||||
|
||||
return (
|
||||
<group>
|
||||
<StaticArmorSceneComponents group="hull" />
|
||||
<StaticArmorSceneComponents group="chassis" />
|
||||
<StaticArmorSceneComponent group="hull" />
|
||||
<StaticArmorSceneComponent group="chassis" />
|
||||
<group position={[0.7, 1.6, 0]}>
|
||||
<StaticArmorSceneComponents group="turret_01" />
|
||||
<StaticArmorSceneComponent group="turret_01" />
|
||||
<group position={[1, 0.36, 0]}>
|
||||
<StaticArmorSceneComponents group="gun_01" />
|
||||
<StaticArmorSceneComponent group="gun_01" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
+4
-4
@@ -12,16 +12,16 @@ import { Duel } from '../../../stores/duel';
|
||||
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
|
||||
import { TankopediaPersistent } from '../../../stores/tankopediaPersistent';
|
||||
|
||||
interface StaticArmorSceneComponentsProps {
|
||||
interface StaticArmorSceneComponentsProp {
|
||||
group: string;
|
||||
}
|
||||
|
||||
const moduleColor = new Color(192 / 255, 192 / 255, 192 / 255);
|
||||
const groupNameRegex = /([a-z]+)(_\d+)?/;
|
||||
export const groupNameRegex = /([a-z]+)(_\d+)?/;
|
||||
|
||||
export function StaticArmorSceneComponents({
|
||||
export function StaticArmorSceneComponent({
|
||||
group,
|
||||
}: StaticArmorSceneComponentsProps) {
|
||||
}: StaticArmorSceneComponentsProp) {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
const showModules = TankopediaPersistent.use((state) => state.showModules);
|
||||
const showArmorScreen = TankopediaPersistent.use(
|
||||
@@ -395,6 +395,15 @@ export function Options({ canvas }: OptionsProps) {
|
||||
</Flex>
|
||||
</Tooltip>
|
||||
</SegmentedControl.Item>
|
||||
<SegmentedControl.Item value={`${TankopediaDisplay.Dissector}`}>
|
||||
<Tooltip
|
||||
content={strings.website.tools.tanks.sandbox.dissector.name}
|
||||
>
|
||||
<Flex height="100%" align="center">
|
||||
<img src={imgur('ErJEWbY')} style={{ height: '1.25em' }} />
|
||||
</Flex>
|
||||
</Tooltip>
|
||||
</SegmentedControl.Item>
|
||||
{/* <SegmentedControl.Item value={`${TankopediaDisplay.ShootingRange}`}>
|
||||
<Tooltip content="Shooting range">
|
||||
<Flex height="100%" align="center">
|
||||
|
||||
+2
-1
@@ -20,7 +20,8 @@ export function Lighting() {
|
||||
environmentRotation={new Euler(0, degToRad(180), 0)}
|
||||
/>
|
||||
)}
|
||||
{display === TankopediaDisplay.StaticArmor && (
|
||||
{(display === TankopediaDisplay.StaticArmor ||
|
||||
display === TankopediaDisplay.Dissector) && (
|
||||
<Environment preset="lobby" />
|
||||
)}
|
||||
{display === TankopediaDisplay.ShootingRange && (
|
||||
|
||||
+4
-1
@@ -1,12 +1,14 @@
|
||||
import { BLITZKIT_TANK_ICON_SIZE } from '@blitzkit/core';
|
||||
import { Canvas } from '@react-three/fiber';
|
||||
import { forwardRef, Suspense, useImperativeHandle, useRef } from 'react';
|
||||
import { Plane, Vector3 } from 'three';
|
||||
import { useOnScreen } from '../../../../../hooks/useOnScreen';
|
||||
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
|
||||
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
|
||||
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
|
||||
import { Armor } from '../../../../Armor';
|
||||
import { ArmorPlateDisplay } from '../../../../Armor/components/ArmorPlateDisplay';
|
||||
import { Dissector } from '../../../../Armor/components/Dissector';
|
||||
import { ShotDisplay } from '../../../../Armor/components/ShotDisplay';
|
||||
import { StaticArmor } from '../../../../Armor/components/StaticArmor';
|
||||
import { AutoClear } from './components/AutoClear';
|
||||
@@ -158,7 +160,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
: 'never'
|
||||
}
|
||||
gl={{
|
||||
clippingPlanes: [],
|
||||
clippingPlanes: [new Plane(new Vector3(0, 0, 1))],
|
||||
localClippingEnabled: true,
|
||||
preserveDrawingBuffer: true,
|
||||
}}
|
||||
@@ -190,6 +192,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
<Suspense fallback={<ModelLoader />}>
|
||||
{display === TankopediaDisplay.DynamicArmor && <Armor />}
|
||||
{display === TankopediaDisplay.StaticArmor && <StaticArmor />}
|
||||
{display === TankopediaDisplay.Dissector && <Dissector />}
|
||||
<Lighting />
|
||||
</Suspense>
|
||||
</Canvas>
|
||||
|
||||
@@ -137,7 +137,7 @@ export const TankopediaEphemeral = createContextualStore(
|
||||
armor,
|
||||
controlsEnabled: true,
|
||||
xpMultiplier: 1,
|
||||
display: TankopediaDisplay.StaticArmor,
|
||||
display: TankopediaDisplay.Dissector,
|
||||
})),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -37,5 +37,6 @@ export enum TankopediaDisplay {
|
||||
Model,
|
||||
DynamicArmor,
|
||||
StaticArmor,
|
||||
Dissector,
|
||||
ShootingRange,
|
||||
}
|
||||
Reference in new issue
Block a user