feat: elevation

This commit is contained in:
TrèsAbhi committed 2025-08-09 12:31:36 -05:00
1 parent e6029157aa
commit 6b7f8049fe
6 files changed
+117 -53

No files matched your search

@@ -1,6 +1,6 @@
import type { AssaultRanges } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { Box, Card, Flex, Text } from '@radix-ui/themes';
import { Box, Flex, Text } from '@radix-ui/themes';
import { clamp } from 'three/src/math/MathUtils.js';
import {
fakeLogSquishyHigh,
@@ -9,6 +9,7 @@ import {
import type { TankCharacteristics } from '../../../../../../../core/blitzkit/tankCharacteristics';
import { Var } from '../../../../../../../core/radix/var';
import { useLocale } from '../../../../../../../hooks/useLocale';
import { VisualizerCard } from '../VisualizerCard';
import { AssaultCursor } from './components/Cursor';
interface Props {
@@ -29,7 +30,7 @@ export function AssaultRangesVisualizer({ ranges: _ranges, stats }: Props) {
const { strings } = useLocale();
return (
<Card mb="6" variant="classic" style={{ aspectRatio: '1 / 1' }}>
<VisualizerCard>
<Flex
position="absolute"
top="0"
@@ -152,6 +153,6 @@ export function AssaultRangesVisualizer({ ranges: _ranges, stats }: Props) {
</Flex>
</Flex>
</Flex>
</Card>
</VisualizerCard>
);
}
@@ -1,14 +1,14 @@
import { Card } from '@radix-ui/themes';
import { awaitableModelDefinitions } from '../../../../../../../core/awaitables/modelDefinitions';
import { DEFAULT_PITCH_TRANSITION } from '../../../../../../../core/blitz/applyPitchYawLimits';
import { Duel } from '../../../../../../../stores/duel';
import { VisualizerCard } from '../VisualizerCard';
const MAX_MAG = 20;
const ANGLE_COEFFICIENT = 1 / 10;
const modelDefinition = await awaitableModelDefinitions;
function mag(x: number) {
return (x / MAX_MAG + 1) / 2;
return ((2 / Math.PI) * Math.atan(ANGLE_COEFFICIENT * x) + 1) / 2;
}
function c(thetaDeg: number, m = 1) {
@@ -34,18 +34,18 @@ export function GunFlexibilityVisualizer() {
let d = '';
// right
const ms = mag(p.max);
const mo = mag(p.max);
if (y) {
d += `M ${c(90 - y.max, ms)}`;
d += `M ${c(90 - y.max, mo)}`;
} else if (b) {
d += `M ${c(-90 + b.range / 2 + t, ms)}`;
d += `M ${c(-90 + b.range / 2 + t, mo)}`;
} else {
d += `M ${c(-90 / 2, ms)}`;
d += `M ${c(-90 / 2, mo)}`;
}
if (f) {
d += `A ${ms} ${ms} 0 0 0 ${c(90 - f.range / 2 - t, ms)}`;
d += `A ${mo} ${mo} 0 0 0 ${c(90 - f.range / 2 - t, mo)}`;
} else {
d += `A ${ms} ${ms} 0 0 0 ${c(90 / 2, ms)}`;
d += `A ${mo} ${mo} 0 0 0 ${c(90 / 2, mo)}`;
}
// front
@@ -57,16 +57,16 @@ export function GunFlexibilityVisualizer() {
// left
if (f) {
d += `L ${c(90 + f.range / 2 + t, ms)}`;
d += `L ${c(90 + f.range / 2 + t, mo)}`;
} else {
d += `L ${c(90 / 2, ms)}`;
d += `L ${c(90 / 2, mo)}`;
}
if (y) {
d += `A ${ms} ${ms} 0 0 0 ${c(90 - y.min, ms)}`;
d += `A ${mo} ${mo} 0 0 0 ${c(90 - y.min, mo)}`;
} else if (b) {
d += `A ${ms} ${ms} 0 0 0 ${c(-90 - b.range / 2 - t, ms)}`;
d += `A ${mo} ${mo} 0 0 0 ${c(-90 - b.range / 2 - t, mo)}`;
} else {
d += `A ${ms} ${ms} 0 0 0 ${c(-90 / 2, ms)}`;
d += `A ${mo} ${mo} 0 0 0 ${c(-90 / 2, mo)}`;
}
// back
@@ -78,8 +78,53 @@ export function GunFlexibilityVisualizer() {
d += `Z`;
// right
const mi = mag(p.min);
if (y) {
d += `M ${c(90 - y.max, mi)}`;
} else if (b) {
d += `M ${c(-90 + b.range / 2 + t, mi)}`;
} else {
d += `M ${c(-90 / 2, mi)}`;
}
if (f) {
d += `A ${mi} ${mi} 0 0 0 ${c(90 - f.range / 2 - t, mi)}`;
} else {
d += `A ${mi} ${mi} 0 0 0 ${c(90 / 2, mi)}`;
}
// front
if (f) {
const m = mag(f.min);
d += `L ${c(90 - f.range / 2, m)}`;
d += `A ${m} ${m} 0 0 0 ${c(90 + f.range / 2, m)}`;
}
// left
if (f) {
d += `L ${c(90 + f.range / 2 + t, mi)}`;
} else {
d += `L ${c(90 / 2, mi)}`;
}
if (y) {
d += `A ${mi} ${mi} 0 0 0 ${c(90 - y.min, mi)}`;
} else if (b) {
d += `A ${mi} ${mi} 0 0 0 ${c(-90 - b.range / 2 - t, mi)}`;
} else {
d += `A ${mi} ${mi} 0 0 0 ${c(-90 / 2, mi)}`;
}
// back
if (!y && b) {
const m = mag(b.min);
d += `L ${c(-90 - b.range / 2, m)}`;
d += `A ${m} ${m} 0 0 0 ${c(-90 + b.range / 2, m)}`;
}
d += `Z`;
return (
<Card style={{ aspectRatio: '1 / 1' }} variant="classic">
<VisualizerCard>
<svg
style={{
position: 'absolute',
@@ -91,19 +136,23 @@ export function GunFlexibilityVisualizer() {
viewBox="-1 -1 2 2"
>
<path
stroke="var(--gray-11)"
strokeWidth="0.01px"
fill="var(--gray-9)"
fillRule="evenodd"
fill="var(--gray-5)"
stroke="var(--gray-7)"
strokeWidth="1px"
vectorEffect="non-scaling-stroke"
d={d}
/>
<path
stroke="var(--gray-2)"
stroke="var(--gray-10)"
fill="transparent"
strokeWidth="0.01px"
strokeDasharray="0.05 0.01"
strokeWidth="1px"
strokeDasharray="0.5rem 0.5rem"
vectorEffect="non-scaling-stroke"
d="M 0.5 0 A 0.5 0.5 0 1 1 -0.5 0 A 0.5 0.5 0 1 1 0.5 0 Z"
/>
</svg>
</Card>
</VisualizerCard>
);
}
@@ -1,10 +1,11 @@
import { type Datum, type Serie } from '@nivo/line';
import { Box, Card } from '@radix-ui/themes';
import { Box } from '@radix-ui/themes';
import { times } from 'lodash-es';
import { Quicklime, type QuicklimeCallback } from 'quicklime';
import { useEffect, useRef } from 'react';
import { Var } from '../../../../../../../core/radix/var';
import type { StatsAcceptorProps } from '../TraverseVisualizer';
import { VisualizerCard } from '../VisualizerCard';
import { Shell } from './components/Shell';
import { Target } from './components/Target';
@@ -51,7 +52,6 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) {
}
function frame() {
const now = Date.now() / 1000;
const dt = now - lastT;
let reload;
@@ -130,7 +130,7 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) {
}, []);
return (
<Card variant="classic" mb="6" style={{ aspectRatio: '1 / 1' }}>
<VisualizerCard>
<Box position="absolute" top="0" left="0" width="100%" height="100%">
<Target />
@@ -220,6 +220,6 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) {
times(stats.shells, (index) => (
<Shell stats={stats} index={index} key={index} />
))}
</Card>
</VisualizerCard>
);
}
@@ -1,12 +1,13 @@
import { asset, isExplosive } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { Box, Card, Code, Flex, Text } from '@radix-ui/themes';
import { Box, Code, Flex, Text } from '@radix-ui/themes';
import { useRef, useState } from 'react';
import { clamp, degToRad, radToDeg } from 'three/src/math/MathUtils.js';
import { Var } from '../../../../../../../core/radix/var';
import { useLocale } from '../../../../../../../hooks/useLocale';
import { Duel } from '../../../../../../../stores/duel';
import type { StatsAcceptorProps } from '../TraverseVisualizer';
import { VisualizerCard } from '../VisualizerCard';
import { ShellSwitcher } from './components/ShellSwitcher';
export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
@@ -26,13 +27,8 @@ export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
return (
<Flex direction="column" mb="6" align="center">
<Card
variant="classic"
style={{
width: '100%',
aspectRatio: '1 / 1',
touchAction: 'none',
}}
<VisualizerCard
style={{ width: '100%' }}
ref={container}
onPointerMove={(event) => {
if (!container.current || explodes) return;
@@ -73,23 +69,23 @@ export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
position="absolute"
style={{
background: `conic-gradient(
at 0 50%,
at 0 50%,
${Var('ruby-a2')},
${Var('ruby-a1')} ${Math.PI / 2 - ricochet}rad,
${Var('ruby-a2')},
${Var('ruby-a1')} ${Math.PI / 2 - ricochet}rad,
${Var('jade-a2')} ${Math.PI / 2 - ricochet}rad,
${Var('jade-a4')} ${Math.PI / 2 - normalization}rad,
${Var('jade-a2')} ${Math.PI / 2 - ricochet}rad,
${Var('jade-a4')} ${Math.PI / 2 - normalization}rad,
${Var('cyan-a5')} ${Math.PI / 2 - normalization}rad,
${Var('cyan-a3')} ${Math.PI / 2 + normalization}rad,
${Var('cyan-a5')} ${Math.PI / 2 - normalization}rad,
${Var('cyan-a3')} ${Math.PI / 2 + normalization}rad,
${Var('jade-a2')} ${Math.PI / 2 + normalization}rad,
${Var('jade-a4')} ${Math.PI / 2 + ricochet}rad,
${Var('jade-a2')} ${Math.PI / 2 + normalization}rad,
${Var('jade-a4')} ${Math.PI / 2 + ricochet}rad,
${Var('ruby-a1')} ${Math.PI / 2 + ricochet}rad,
${Var('ruby-a2')} 180deg
`,
${Var('ruby-a1')} ${Math.PI / 2 + ricochet}rad,
${Var('ruby-a2')} 180deg
`,
}}
/>
@@ -262,7 +258,7 @@ export function RicochetVisualizer({ stats }: StatsAcceptorProps) {
</Text>
</Flex>
)}
</Card>
</VisualizerCard>
<ShellSwitcher />
</Flex>
@@ -1,8 +1,9 @@
import { literals } from '@blitzkit/i18n';
import { Card, Checkbox, Code, Flex, Tabs, Text } from '@radix-ui/themes';
import { Checkbox, Code, Flex, Tabs, Text } from '@radix-ui/themes';
import { useEffect, useRef, useState } from 'react';
import type { TankCharacteristics } from '../../../../../../../core/blitzkit/tankCharacteristics';
import { useLocale } from '../../../../../../../hooks/useLocale';
import { VisualizerCard } from '../VisualizerCard';
export interface StatsAcceptorProps {
stats: TankCharacteristics;
@@ -58,7 +59,7 @@ export function TraverseVisualizer({ stats }: StatsAcceptorProps) {
}, [terrain, turretSpeedDeg, hullSpeedDeg]);
return (
<Card variant="classic" style={{ aspectRatio: '1 / 1' }}>
<VisualizerCard>
<div
ref={hull}
style={{
@@ -188,6 +189,6 @@ export function TraverseVisualizer({ stats }: StatsAcceptorProps) {
</Flex>
</Flex>
)}
</Card>
</VisualizerCard>
);
}
@@ -0,0 +1,17 @@
import { Card, type CardProps } from '@radix-ui/themes';
import { forwardRef } from 'react';
export const VisualizerCard = forwardRef<HTMLDivElement, CardProps>(
({ style, ...props }, ref) => {
return (
<Card
ref={ref}
variant="classic"
mt="4"
mb="6"
style={{ aspectRatio: '1 / 1', ...style }}
{...props}
/>
);
},
);